From 1f033aa0c0f5f21ea3d58274da1e761e17b131e9 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Tue, 19 Mar 2024 20:29:13 +0000 Subject: [PATCH 01/36] Fix --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 3 +++ 1 file changed, 3 insertions(+) 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 679f097ee65..a2f1b30f6bc 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -126,6 +126,9 @@ pub fn get_notes( if options.limit != 0 { assert(num_notes <= options.limit, "Invalid number of return notes."); } + + assert(num_notes != 0, "Cannot return zero notes"); + opt_notes } From 42ca60a697aa39467e51335cac09024945d57aeb Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Tue, 19 Mar 2024 20:41:06 +0000 Subject: [PATCH 02/36] fix --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) 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 a2f1b30f6bc..c28e1c6dd3f 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -100,7 +100,9 @@ pub fn get_notes( storage_slot: Field, options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { - let opt_notes = get_notes_internal(storage_slot, options); + let mut opt_notes = get_notes_internal(storage_slot, options); + let mut write_index = 0; + let mut num_notes = 0; let mut prev_fields = [0; N]; for i in 0..opt_notes.len() { @@ -121,6 +123,13 @@ pub fn get_notes( context.push_note_hash_read_request(note_hash_for_read_request); num_notes += 1; + + if (write_index != i) { + opt_notes[write_index] = Option::some(note); + opt_notes[i] = Option::none(); + } + + write_index += 1; }; } if options.limit != 0 { From da6378af54826e813b7057780f677919b17ab5ee Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 20 Mar 2024 00:48:17 +0000 Subject: [PATCH 03/36] fix --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 2 -- 1 file changed, 2 deletions(-) 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 c28e1c6dd3f..6d4b3d00ebd 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -136,8 +136,6 @@ pub fn get_notes( assert(num_notes <= options.limit, "Invalid number of return notes."); } - assert(num_notes != 0, "Cannot return zero notes"); - opt_notes } From a313ca297b9dc5578a87e85bf72edf5ddfeb281e Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 20 Mar 2024 00:48:54 +0000 Subject: [PATCH 04/36] asdf --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 1 - 1 file changed, 1 deletion(-) 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 6d4b3d00ebd..dabc5435e79 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -135,7 +135,6 @@ pub fn get_notes( if options.limit != 0 { assert(num_notes <= options.limit, "Invalid number of return notes."); } - opt_notes } From b57c607a21c2cfbff6554187e9bb81de6b837098 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 20 Mar 2024 22:00:19 +0000 Subject: [PATCH 05/36] add test --- .../contracts/test_contract/src/main.nr | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) 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 f5139cf61dc..5404dc45766 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -111,6 +111,43 @@ contract Test { emit_unencrypted_log_from_private(&mut context, opt_notes[1].unwrap().value); } + pub fn filter( + notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], + _args: bool + ) -> pub [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { + let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + + selected[1] = notes[0]; + selected[2] = notes[1]; + selected[3] = notes[2]; + selected[5] = notes[3]; + selected[8] = notes[4]; + selected[13] = notes[5]; + selected[21] = notes[6]; + + selected + } + + #[aztec(private)] + fn create_and_get_notes_many_with_filter(storage_slot: Field) { + assert( + storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" + ); + + for i in 0..7 { + let mut note = FieldNote::new(i as Field); + storage.example_set.insert(&mut note, true); + } + + let options = NoteGetterOptions::with_filter(filter, true); + let opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = get_notes(&mut context, storage_slot, options); + + // We can't get the return value of a private function from the outside world in an end to end test, so we + // expose it via an unecrypted log instead. + emit_unencrypted_log_from_private(&mut context, opt_notes[0].unwrap().value); + emit_unencrypted_log_from_private(&mut context, opt_notes[1].unwrap().value); + } + unconstrained fn call_view_notes(storage_slot: Field, active_or_nullified: bool) -> pub Field { assert( storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" From fd364f39d06271ae778797a77acb8d66a379e271 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 21 Mar 2024 17:05:32 +0000 Subject: [PATCH 06/36] add test --- .../contracts/test_contract/src/main.nr | 21 +++++++------ .../end-to-end/src/e2e_note_getter.test.ts | 30 +++++++++++++++++-- 2 files changed, 38 insertions(+), 13 deletions(-) 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 5404dc45766..593237ab854 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -111,7 +111,7 @@ contract Test { emit_unencrypted_log_from_private(&mut context, opt_notes[1].unwrap().value); } - pub fn filter( + pub fn filter_that_creates_sparse_array( notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], _args: bool ) -> pub [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { @@ -129,23 +129,22 @@ contract Test { } #[aztec(private)] - fn create_and_get_notes_many_with_filter(storage_slot: Field) { - assert( - storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" - ); - + pub fn create_and_get_many_notes_with_filter() { for i in 0..7 { let mut note = FieldNote::new(i as Field); - storage.example_set.insert(&mut note, true); + storage.example_set.insert(&mut note, false); } - let options = NoteGetterOptions::with_filter(filter, true); - let opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = get_notes(&mut context, storage_slot, options); + let options = NoteGetterOptions::with_filter(filter_that_creates_sparse_array, true); + // get_notes should collapse this array + let opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = storage.example_set.get_notes(options); // We can't get the return value of a private function from the outside world in an end to end test, so we // expose it via an unecrypted log instead. - emit_unencrypted_log_from_private(&mut context, opt_notes[0].unwrap().value); - emit_unencrypted_log_from_private(&mut context, opt_notes[1].unwrap().value); + for i in 0..7 { + // We verify that the array was collapsed by unwrapping the first 7 values. + emit_unencrypted_log_from_private(&mut context, opt_notes[i].unwrap().value); + } } unconstrained fn call_view_notes(storage_slot: Field, active_or_nullified: bool) -> pub Field { diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 6641b391149..1e6ed1b4105 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -1,4 +1,4 @@ -import { AztecAddress, Comparator, Fr, Wallet, toBigInt } from '@aztec/aztec.js'; +import { AztecAddress, AztecNode, Comparator, Fr, Wallet, toBigInt } from '@aztec/aztec.js'; import { DocsExampleContract, TestContract } from '@aztec/noir-contracts.js'; import { setup } from './fixtures/utils.js'; @@ -16,11 +16,12 @@ function unwrapOptions(options: NoirOption[]): T[] { } describe('e2e_note_getter', () => { + let aztecNode: AztecNode; let wallet: Wallet; let teardown: () => Promise; beforeAll(async () => { - ({ teardown, wallet } = await setup()); + ({ teardown, wallet, aztecNode } = await setup()); }, 25_000); afterAll(() => teardown()); @@ -252,6 +253,31 @@ describe('e2e_note_getter', () => { expect(viewNotesManyResult).toEqual(getNotesManyResult); expect(viewNotesManyResult.sort()).toEqual([BigInt(VALUE), BigInt(VALUE + 1)]); }, 45_000); + + it('returns nullified notes', async () => { + await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); + await contract.methods.call_destroy_note(storageSlot).send().wait(); + + await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); + }, 30_000); + + it('get_notes should collapse sparse arrays', async () => { + // We call the function that creates a sparse array in get_notes_internal, using the filter + // It then gets the notes from the set and confirms that the array is not sparse and has been handled by get_notes + const tx = await contract.methods.create_and_get_many_notes_with_filter().send().wait(); + const block = await aztecNode.getBlock(tx.blockNumber!); + + // We want to verify that there are: + // 2 tx's in the block + expect(block!.body.unencryptedLogs.txLogs.length).toStrictEqual(2); + // our first tx has two function logs + expect(block?.body.unencryptedLogs.txLogs[0].functionLogs.length).toStrictEqual(2); + // our second function logs has 7 individual logs that were emitted from create_and_get_notes_many_with_filter + expect(block!.body.unencryptedLogs.txLogs[0].functionLogs[1].logs.length).toStrictEqual(7); + + const unencryptedLogs = block?.body.unencryptedLogs.txLogs.flatMap(txLog => txLog.functionLogs.flatMap(functionLog => functionLog.logs.map(log => log.toString('hex').substring(log.length * 2 -2)))); + expect(unencryptedLogs).toStrictEqual(['00', '01', '02', '03', '04', '05','06']); + }, 45_000); }); }); }); From 7b5929fc5c5142a1ac19fcabebd60ae7d4d1c533 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 21 Mar 2024 17:19:47 +0000 Subject: [PATCH 07/36] fix --- yarn-project/end-to-end/src/e2e_note_getter.test.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 1e6ed1b4105..ee16554daa8 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -254,13 +254,6 @@ describe('e2e_note_getter', () => { expect(viewNotesManyResult.sort()).toEqual([BigInt(VALUE), BigInt(VALUE + 1)]); }, 45_000); - it('returns nullified notes', async () => { - await contract.methods.call_create_note(VALUE, owner, storageSlot).send().wait(); - await contract.methods.call_destroy_note(storageSlot).send().wait(); - - await assertNoteIsReturned(storageSlot, VALUE, activeOrNullified); - }, 30_000); - it('get_notes should collapse sparse arrays', async () => { // We call the function that creates a sparse array in get_notes_internal, using the filter // It then gets the notes from the set and confirms that the array is not sparse and has been handled by get_notes From 5473fd1d236edeacf65b171ba4e2ca974ed90815 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 21 Mar 2024 17:45:48 +0000 Subject: [PATCH 08/36] formatting fix --- yarn-project/end-to-end/src/e2e_note_getter.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index ee16554daa8..162c453929d 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -268,8 +268,12 @@ describe('e2e_note_getter', () => { // our second function logs has 7 individual logs that were emitted from create_and_get_notes_many_with_filter expect(block!.body.unencryptedLogs.txLogs[0].functionLogs[1].logs.length).toStrictEqual(7); - const unencryptedLogs = block?.body.unencryptedLogs.txLogs.flatMap(txLog => txLog.functionLogs.flatMap(functionLog => functionLog.logs.map(log => log.toString('hex').substring(log.length * 2 -2)))); - expect(unencryptedLogs).toStrictEqual(['00', '01', '02', '03', '04', '05','06']); + const unencryptedLogs = block?.body.unencryptedLogs.txLogs.flatMap(txLog => + txLog.functionLogs.flatMap(functionLog => + functionLog.logs.map(log => log.toString('hex').substring(log.length * 2 - 2)), + ), + ); + expect(unencryptedLogs).toStrictEqual(['00', '01', '02', '03', '04', '05', '06']); }, 45_000); }); }); From fdd02190ea7f49db6a1c4c27057379b2d15b7dab Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 12:37:27 +0000 Subject: [PATCH 09/36] Add comments --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 3 +++ 1 file changed, 3 insertions(+) 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 dabc5435e79..c659606b472 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -124,6 +124,9 @@ pub fn get_notes( num_notes += 1; + // The below code is used to collapse a sparse array into one where the values are guaranteed to be at the front of the array + // The condition activates if at any point there was a gap in the array, (i was advanced; by not write_index) + // In this case we move our note at i to the write_index (the last empty spot in the array), and fill the last read index with nothing. if (write_index != i) { opt_notes[write_index] = Option::some(note); opt_notes[i] = Option::none(); From 717eb4a4f6306641218fbbbad881b762fe572fbd Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 12:48:42 +0000 Subject: [PATCH 10/36] tweak --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 12 +++++------- .../contracts/test_contract/src/main.nr | 2 ++ 2 files changed, 7 insertions(+), 7 deletions(-) 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 c659606b472..70ade0d417b 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -101,6 +101,8 @@ pub fn get_notes( options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let mut opt_notes = get_notes_internal(storage_slot, options); + + let mut returned_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut write_index = 0; let mut num_notes = 0; @@ -126,19 +128,15 @@ pub fn get_notes( // The below code is used to collapse a sparse array into one where the values are guaranteed to be at the front of the array // The condition activates if at any point there was a gap in the array, (i was advanced; by not write_index) - // In this case we move our note at i to the write_index (the last empty spot in the array), and fill the last read index with nothing. - if (write_index != i) { - opt_notes[write_index] = Option::some(note); - opt_notes[i] = Option::none(); - } - + // In this case we move our note at i to returned_notes at write_index + returned_notes[write_index] = Option::some(note); write_index += 1; }; } if options.limit != 0 { assert(num_notes <= options.limit, "Invalid number of return notes."); } - opt_notes + returned_notes } unconstrained fn get_note_internal(storage_slot: Field) -> Note where Note: NoteInterface { 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 593237ab854..058ff52b132 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -115,6 +115,7 @@ contract Test { notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], _args: bool ) -> pub [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { + // selected is our returned sparse array let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; selected[1] = notes[0]; @@ -130,6 +131,7 @@ contract Test { #[aztec(private)] pub fn create_and_get_many_notes_with_filter() { + // We create 7 notes to test getting them later for i in 0..7 { let mut note = FieldNote::new(i as Field); storage.example_set.insert(&mut note, false); From 276dc0c29e9bc4fea1a405d3861bac06b06a108d Mon Sep 17 00:00:00 2001 From: Miranda Wood Date: Thu, 21 Mar 2024 18:15:44 +0000 Subject: [PATCH 11/36] feat: truncate SHA hashes inside circuits (#5160) Will close #2019 This PR converts SHA hashing inside noir circuits from outputting 2 128-bit fields to outputting 1 248-bit field. To fit inside the field, we truncate one byte. --- ### Noir Changes The constant `NUM_FIELDS_PER_SHA256` is now 1, so any hardcoded test values and function returns have been changed to use an array of one. I've kept it as an array rather than a single `Fr` to minimise changes across the repo and ensure if we want to revert `NUM_FIELDS_PER_SHA256` in future, it won't be so painful. However, we can also just use a single `Fr` if that's preferable. `TX_EFFECTS_HASH_LOG_FIELDS` Methods: - `field_from_bytes_32_trunc`: Converts a 32 byte array to a 31 byte field element (useful for comparisons with new `sha256_to_field`), tests in `types/src/utils/field.nr`. - `sha256_to_field`: Uses the same method as the previous version to convert the sha result (BE) bytes array to field, but leaves out the final byte. - `accumulate_sha256`: Used almost exclusively for enc/unenc logs hashing - takes in 2 31 byte field elements, assumed to be outputs of a previous sha hash, pads to 32 bytes and hashes them with `sha256_to_field` as a 64 byte array. Note that as before, other circuits that use sha (like tx effects hash and messages hash) do not use this method and instead create a flat byte array, then call `sha256_to_field`. --- ### L1 Contract Changes To match the Noir method, the `sha256ToField` function now truncates a byte and prepends a blank byte. Not prepending the blank byte means changing many struct fields from `bytes32` to `bytes31`. This (IIRC) is the same gas cost and creates more awkward encoding, so I kept the length with a blank byte. This also changes the slither file, as I removed some of the old encoding which flagged with new encoding... which also flags. ~Only the 'leaves' used in computing the `txsHash` in `TxsDecoder` and logs hashes have been changed to 31 bytes to match the Noir SHA accumulation (since we are repeating hashes of hashes).~ ~The TS code (see below) does pack the Header struct with 31 bytes per SHA, so we must shift the decoding in HeaderLib` by 3 bytes.~ As of 21.3, there have been a lot of changes in master to the way the txs effect hash (formerly calldata hash/txs hash) is calculated. Plus, now we actually recalculate the in/outHash (i.e. the root of the sha tree of messages) in the contract, so I have reverted to using 32 bytes everywhere with a prepended blank byte. --- ### TS Changes All `.hash()` methods which are also computed in the circuit have been changed to match the Noir code. In most places this just means truncating a byte with `.subarray(0, 31)` on the buffer. ~The `ContentCommitment` serialise/deserialise methods have been modified, as keeping `NUM_BYTES_PER_SHA256 = 32` caused a lot of issues in the background. Changing it to 31 to match Noir does mean slightly different encoding, but many fewer changes across the repo (and hopefully less confusion).~ As of 21.3, due to changes in master, it's now cleaner to keep `NUM_BYTES_PER_SHA256 = 32` and be sure to truncate and pad all SHA hashes which touch the Noir circuits. Since I've kept the hash output as an array of one in Noir, there are many tuples of one in ts (for the above reasoning) - this can be changed if preferable. Methods: - `toTruncField`: Mirrors Noir's `field_from_bytes_32_trunc` to convert to a field element - used in place of old method `to2Fields` (tested in `free_funcs.test.ts`). - `fromTruncField`: Converts the above back to a 31 byte buffer (tested as above). --- --- l1-contracts/slither_output.md | 96 ++++++++++--------- .../src/core/libraries/ConstantsGen.sol | 12 +-- l1-contracts/src/core/libraries/Hash.sol | 6 +- l1-contracts/src/core/libraries/MerkleLib.sol | 5 +- .../core/libraries/decoders/TxsDecoder.sol | 11 ++- .../messagebridge/frontier_tree/Frontier.sol | 13 ++- l1-contracts/test/Parity.t.sol | 30 +++--- l1-contracts/test/decoders/Decoders.t.sol | 29 +++--- l1-contracts/test/fixtures/empty_block_0.json | 20 ++-- l1-contracts/test/fixtures/empty_block_1.json | 22 ++--- l1-contracts/test/fixtures/mixed_block_0.json | 22 ++--- l1-contracts/test/fixtures/mixed_block_1.json | 26 ++--- l1-contracts/test/merkle/Naive.sol | 10 +- l1-contracts/test/merkle/Naive.t.sol | 17 ++-- .../aztec/src/context/public_context.nr | 2 +- .../aztec-nr/aztec/src/oracle/logs.nr | 4 +- .../parity-lib/src/base/base_parity_inputs.nr | 31 ++---- .../parity-lib/src/parity_public_inputs.nr | 3 +- .../parity-lib/src/root/root_parity_inputs.nr | 19 ++-- .../src/utils/sha256_merkle_tree.nr | 29 +++--- .../src/private_kernel_init.nr | 8 +- .../src/private_kernel_inner.nr | 8 +- .../crates/public-kernel-lib/src/common.nr | 6 +- .../src/public_kernel_app_logic.nr | 6 +- .../src/public_kernel_setup.nr | 6 +- .../src/public_kernel_teardown.nr | 6 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 13 +-- .../crates/rollup-lib/src/components.nr | 59 ++++-------- .../src/merge/merge_rollup_inputs.nr | 7 +- .../crates/rollup-lib/src/root.nr | 21 ++-- .../rollup-lib/src/root/root_rollup_inputs.nr | 4 +- .../src/tests/previous_rollup_data.nr | 8 +- .../accumulated_revertible_data_builder.nr | 2 +- .../combined_accumulated_data.nr | 2 +- .../combined_accumulated_data_builder.nr | 2 +- .../private_accumulated_revertible_data.nr | 2 +- .../public_accumulated_revertible_data.nr | 2 +- .../types/src/abis/private_call_stack_item.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 4 +- .../types/src/abis/public_call_stack_item.nr | 4 +- .../src/abis/public_circuit_public_inputs.nr | 4 +- .../crates/types/src/constants.nr | 14 +-- .../crates/types/src/content_commitment.nr | 2 +- .../crates/types/src/hash.nr | 75 +++++++-------- .../crates/types/src/header.nr | 4 +- .../crates/types/src/tests/fixtures.nr | 2 +- .../private_circuit_public_inputs_builder.nr | 2 +- .../public_circuit_public_inputs_builder.nr | 1 + .../crates/types/src/utils/field.nr | 41 ++++++++ noir/noir-repo/noir_stdlib/src/field.nr | 2 +- .../aztec-node/src/aztec-node/server.ts | 6 +- yarn-project/circuit-types/src/body.ts | 4 +- .../circuit-types/src/l2_block.test.ts | 8 +- yarn-project/circuit-types/src/l2_block.ts | 4 +- .../src/logs/function_l2_logs.ts | 4 +- .../circuit-types/src/logs/tx_l2_logs.ts | 4 +- .../src/messaging/l1_to_l2_message.ts | 4 +- .../circuit-types/src/mocks_to_purge.ts | 5 +- yarn-project/circuit-types/src/tx_effect.ts | 13 ++- yarn-project/circuits.js/src/constants.gen.ts | 12 +-- .../__snapshots__/contract_class.test.ts.snap | 10 +- .../circuits.js/src/contract/artifact_hash.ts | 2 + .../structs/__snapshots__/header.test.ts.snap | 4 +- .../private_call_stack_item.test.ts.snap | 4 +- ...private_circuit_public_inputs.test.ts.snap | 4 +- .../public_call_stack_item.test.ts.snap | 6 +- .../public_circuit_public_inputs.test.ts.snap | 4 +- .../src/structs/content_commitment.ts | 20 ++-- .../kernel/combined_accumulated_data.ts | 24 ++--- .../structs/parity/parity_public_inputs.ts | 8 +- .../structs/public_circuit_public_inputs.ts | 4 +- .../base_or_merge_rollup_public_inputs.ts | 10 +- .../circuits.js/src/tests/factories.ts | 20 ++-- .../src/e2e_cross_chain_messaging.test.ts | 10 +- .../end-to-end/src/e2e_outbox.test.ts | 13 ++- .../end-to-end/src/e2e_p2p_network.test.ts | 2 +- .../e2e_public_cross_chain_messaging.test.ts | 14 +-- .../src/integration_l1_publisher.test.ts | 27 ++---- .../src/shared/cross_chain_test_harness.ts | 9 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 65 ++++++------- .../src/serialize/free_funcs.test.ts | 18 +++- .../foundation/src/serialize/free_funcs.ts | 42 ++++++++ yarn-project/merkle-tree/src/sha_256.ts | 24 +++++ .../src/__snapshots__/index.test.ts.snap | 36 ++++--- .../nested-call-private-kernel-init.hex | 2 +- .../nested-call-private-kernel-inner.hex | 2 +- .../nested-call-private-kernel-ordering.hex | 2 +- .../src/type_conversion.ts | 26 ++--- yarn-project/scripts/package.local.json | 2 +- .../block_builder/solo_block_builder.test.ts | 10 +- .../src/publisher/viem-tx-sender.ts | 2 +- .../src/sequencer/abstract_phase_manager.ts | 4 +- .../src/sequencer/processed_tx.ts | 11 +-- .../src/sequencer/public_processor.test.ts | 14 +-- .../simulator/src/client/private_execution.ts | 6 +- yarn-project/simulator/src/test/utils.ts | 4 +- .../server_world_state_synchronizer.test.ts | 4 +- .../server_world_state_synchronizer.ts | 9 +- 98 files changed, 679 insertions(+), 589 deletions(-) diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 11f0df12e5e..9b23244910e 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -1,7 +1,7 @@ Summary - [pess-unprotected-setter](#pess-unprotected-setter) (1 results) (High) - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - - [pess-dubious-typecast](#pess-dubious-typecast) (3 results) (Medium) + - [pess-dubious-typecast](#pess-dubious-typecast) (4 results) (Medium) - [missing-zero-check](#missing-zero-check) (2 results) (Low) - [reentrancy-events](#reentrancy-events) (2 results) (Low) - [timestamp](#timestamp) (1 results) (Low) @@ -40,20 +40,28 @@ src/core/libraries/decoders/TxsDecoder.sol#L78 Impact: Medium Confidence: High - [ ] ID-3 -Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L333-L335): - bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L334) +Dubious typecast in [Hash.sha256ToField(bytes)](src/core/libraries/Hash.sol#L42-L44): + bytes32 => bytes31 casting occurs in [bytes32(bytes.concat(new bytes(1),bytes31(sha256(bytes)(_data))))](src/core/libraries/Hash.sol#L43) + bytes => bytes32 casting occurs in [bytes32(bytes.concat(new bytes(1),bytes31(sha256(bytes)(_data))))](src/core/libraries/Hash.sol#L43) -src/core/libraries/decoders/TxsDecoder.sol#L333-L335 +src/core/libraries/Hash.sol#L42-L44 - [ ] ID-4 -Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L343-L345): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L344) +Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L334-L336): + bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L335) -src/core/libraries/decoders/TxsDecoder.sol#L343-L345 +src/core/libraries/decoders/TxsDecoder.sol#L334-L336 - [ ] ID-5 +Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L344-L346): + bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L345) + +src/core/libraries/decoders/TxsDecoder.sol#L344-L346 + + + - [ ] ID-6 Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L143-L184): bytes => bytes32 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L151-L153) bytes => bytes4 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L151-L153) @@ -82,14 +90,14 @@ src/core/libraries/HeaderLib.sol#L143-L184 ## missing-zero-check Impact: Low Confidence: Medium - - [ ] ID-6 + - [ ] ID-7 [Inbox.constructor(address,uint256)._rollup](src/core/messagebridge/Inbox.sol#L40) lacks a zero-check on : - [ROLLUP = _rollup](src/core/messagebridge/Inbox.sol#L41) src/core/messagebridge/Inbox.sol#L40 - - [ ] ID-7 + - [ ] ID-8 [Outbox.constructor(address)._rollup](src/core/messagebridge/Outbox.sol#L31) lacks a zero-check on : - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/Outbox.sol#L32) @@ -99,7 +107,7 @@ src/core/messagebridge/Outbox.sol#L31 ## reentrancy-events Impact: Low Confidence: Medium - - [ ] ID-8 + - [ ] ID-9 Reentrancy in [Rollup.process(bytes,bytes32,bytes)](src/core/Rollup.sol#L58-L96): External calls: - [inHash = INBOX.consume()](src/core/Rollup.sol#L83) @@ -110,7 +118,7 @@ Reentrancy in [Rollup.process(bytes,bytes32,bytes)](src/core/Rollup.sol#L58-L96) src/core/Rollup.sol#L58-L96 - - [ ] ID-9 + - [ ] ID-10 Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L61-L95): External calls: - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/Inbox.sol#L91) @@ -123,7 +131,7 @@ src/core/messagebridge/Inbox.sol#L61-L95 ## timestamp Impact: Low Confidence: Medium - - [ ] ID-10 + - [ ] ID-11 [HeaderLib.validate(HeaderLib.Header,uint256,uint256,bytes32)](src/core/libraries/HeaderLib.sol#L106-L136) uses timestamp for comparisons Dangerous comparisons: - [_header.globalVariables.timestamp > block.timestamp](src/core/libraries/HeaderLib.sol#L120) @@ -134,35 +142,35 @@ src/core/libraries/HeaderLib.sol#L106-L136 ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-11 -The following public functions could be turned into external in [FrontierMerkle](src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93) contract: - [FrontierMerkle.constructor(uint256)](src/core/messagebridge/frontier_tree/Frontier.sol#L19-L27) + - [ ] ID-12 +The following public functions could be turned into external in [FrontierMerkle](src/core/messagebridge/frontier_tree/Frontier.sol#L12-L98) contract: + [FrontierMerkle.constructor(uint256)](src/core/messagebridge/frontier_tree/Frontier.sol#L24-L32) -src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 +src/core/messagebridge/frontier_tree/Frontier.sol#L12-L98 - - [ ] ID-12 + - [ ] ID-13 The following public functions could be turned into external in [Registry](src/core/messagebridge/Registry.sol#L22-L129) contract: [Registry.constructor()](src/core/messagebridge/Registry.sol#L29-L33) src/core/messagebridge/Registry.sol#L22-L129 - - [ ] ID-13 + - [ ] ID-14 The following public functions could be turned into external in [Inbox](src/core/messagebridge/Inbox.sol#L24-L124) contract: [Inbox.constructor(address,uint256)](src/core/messagebridge/Inbox.sol#L40-L51) src/core/messagebridge/Inbox.sol#L24-L124 - - [ ] ID-14 + - [ ] ID-15 The following public functions could be turned into external in [Rollup](src/core/Rollup.sol#L29-L105) contract: [Rollup.constructor(IRegistry,IAvailabilityOracle)](src/core/Rollup.sol#L43-L50) src/core/Rollup.sol#L29-L105 - - [ ] ID-15 + - [ ] ID-16 The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L18-L132) contract: [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L31-L33) @@ -172,41 +180,41 @@ src/core/messagebridge/Outbox.sol#L18-L132 ## assembly Impact: Informational Confidence: High - - [ ] ID-16 -[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L257-L276) uses assembly - - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L264-L266) + - [ ] ID-17 +[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L258-L277) uses assembly + - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L265-L267) -src/core/libraries/decoders/TxsDecoder.sol#L257-L276 +src/core/libraries/decoders/TxsDecoder.sol#L258-L277 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-17 + - [ ] ID-18 [MessageBox.consume(mapping(bytes32 => DataStructures.Entry),bytes32,function(bytes32))](src/core/libraries/MessageBox.sol#L71-L79) is never used and should be removed src/core/libraries/MessageBox.sol#L71-L79 - - [ ] ID-18 + - [ ] ID-19 [MessageBox.contains(mapping(bytes32 => DataStructures.Entry),bytes32)](src/core/libraries/MessageBox.sol#L87-L92) is never used and should be removed src/core/libraries/MessageBox.sol#L87-L92 - - [ ] ID-19 + - [ ] ID-20 [MessageBox.get(mapping(bytes32 => DataStructures.Entry),bytes32,function(bytes32))](src/core/libraries/MessageBox.sol#L104-L112) is never used and should be removed src/core/libraries/MessageBox.sol#L104-L112 - - [ ] ID-20 + - [ ] ID-21 [MessageBox.insert(mapping(bytes32 => DataStructures.Entry),bytes32,uint64,uint32,uint32,function(bytes32,uint64,uint64,uint32,uint32,uint32,uint32))](src/core/libraries/MessageBox.sol#L30-L60) is never used and should be removed src/core/libraries/MessageBox.sol#L30-L60 - - [ ] ID-21 + - [ ] ID-22 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed src/core/libraries/Hash.sol#L52-L54 @@ -215,25 +223,25 @@ src/core/libraries/Hash.sol#L52-L54 ## solc-version Impact: Informational Confidence: High - - [ ] ID-22 + - [ ] ID-23 solc-0.8.23 is not recommended for deployment ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-23 + - [ ] 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) src/core/libraries/ConstantsGen.sol#L130 - - [ ] ID-24 + - [ ] 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) src/core/libraries/ConstantsGen.sol#L110 - - [ ] ID-25 + - [ ] ID-26 Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L32) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L43) src/core/Rollup.sol#L32 @@ -242,7 +250,7 @@ src/core/Rollup.sol#L32 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-26 + - [ ] ID-27 [Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L41) should be constant src/core/Rollup.sol#L41 @@ -251,39 +259,39 @@ src/core/Rollup.sol#L41 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-27 + - [ ] ID-28 In a function [Outbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/Outbox.sol#L44-L64) variable [Outbox.roots](src/core/messagebridge/Outbox.sol#L29) is read multiple times src/core/messagebridge/Outbox.sol#L44-L64 - - [ ] ID-28 + - [ ] ID-29 In a function [Inbox.consume()](src/core/messagebridge/Inbox.sol#L104-L123) variable [Inbox.toConsume](src/core/messagebridge/Inbox.sol#L34) is read multiple times src/core/messagebridge/Inbox.sol#L104-L123 - - [ ] ID-29 + - [ ] ID-30 In a function [Inbox.consume()](src/core/messagebridge/Inbox.sol#L104-L123) variable [Inbox.inProgress](src/core/messagebridge/Inbox.sol#L36) is read multiple times src/core/messagebridge/Inbox.sol#L104-L123 - - [ ] ID-30 -In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76) variable [FrontierMerkle.HEIGHT](src/core/messagebridge/frontier_tree/Frontier.sol#L8) is read multiple times + - [ ] ID-31 +In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81) variable [FrontierMerkle.HEIGHT](src/core/messagebridge/frontier_tree/Frontier.sol#L13) is read multiple times -src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 +src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81 - - [ ] ID-31 + - [ ] ID-32 In a function [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L61-L95) variable [Inbox.inProgress](src/core/messagebridge/Inbox.sol#L36) is read multiple times src/core/messagebridge/Inbox.sol#L61-L95 - - [ ] ID-32 -In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76) variable [FrontierMerkle.frontier](src/core/messagebridge/frontier_tree/Frontier.sol#L13) is read multiple times + - [ ] ID-33 +In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81) variable [FrontierMerkle.frontier](src/core/messagebridge/frontier_tree/Frontier.sol#L18) is read multiple times -src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 +src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81 diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 444c3de0ded..eef15664c7f 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -72,7 +72,7 @@ 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 = 2; + 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; @@ -98,7 +98,7 @@ library Constants { uint256 internal constant VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; uint256 internal constant AZTEC_ADDRESS_LENGTH = 1; uint256 internal constant CALL_CONTEXT_LENGTH = 7; - uint256 internal constant CONTENT_COMMITMENT_LENGTH = 7; + uint256 internal constant CONTENT_COMMITMENT_LENGTH = 4; uint256 internal constant CONTRACT_INSTANCE_LENGTH = 6; uint256 internal constant CONTRACT_STORAGE_READ_LENGTH = 2; uint256 internal constant CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; @@ -106,15 +106,15 @@ library Constants { uint256 internal constant FUNCTION_DATA_LENGTH = 2; uint256 internal constant FUNCTION_LEAF_PREIMAGE_LENGTH = 5; uint256 internal constant GLOBAL_VARIABLES_LENGTH = 6; - uint256 internal constant HEADER_LENGTH = 23; + uint256 internal constant HEADER_LENGTH = 20; uint256 internal constant L1_TO_L2_MESSAGE_LENGTH = 6; uint256 internal constant L2_TO_L1_MESSAGE_LENGTH = 2; uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 6; - uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 213; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 210; - uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 202; + uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 208; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 205; + uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 198; uint256 internal constant STATE_REFERENCE_LENGTH = 8; uint256 internal constant TX_CONTEXT_DATA_LENGTH = 4; uint256 internal constant TX_REQUEST_LENGTH = 8; diff --git a/l1-contracts/src/core/libraries/Hash.sol b/l1-contracts/src/core/libraries/Hash.sol index d859690b1a9..eb572b2fc53 100644 --- a/l1-contracts/src/core/libraries/Hash.sol +++ b/l1-contracts/src/core/libraries/Hash.sol @@ -35,17 +35,17 @@ library Hash { /** * @notice Computes the sha256 hash of the provided data and converts it to a field element - * @dev Using modulo to convert the hash to a field element. + * @dev Truncating one byte to convert the hash to a field element. We prepend a byte rather than cast bytes31(bytes32) to match Noir's to_be_bytes. * @param _data - The bytes to hash * @return The hash of the provided data as a field element */ function sha256ToField(bytes memory _data) internal pure returns (bytes32) { - return bytes32(uint256(sha256(_data)) % Constants.P); + return bytes32(bytes.concat(new bytes(1), bytes31(sha256(_data)))); } /** * @notice Computes the sha256 hash of the provided data and converts it to a field element - * @dev Using modulo to convert the hash to a field element. + * @dev Truncating one byte to convert the hash to a field element. * @param _data - A bytes32 value to hash * @return The hash of the provided data as a field element */ diff --git a/l1-contracts/src/core/libraries/MerkleLib.sol b/l1-contracts/src/core/libraries/MerkleLib.sol index e511fefc9ee..c7ab82502b0 100644 --- a/l1-contracts/src/core/libraries/MerkleLib.sol +++ b/l1-contracts/src/core/libraries/MerkleLib.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.18; import {Errors} from "../libraries/Errors.sol"; +import {Hash} from "../libraries/Hash.sol"; /** * @title Merkle Library @@ -40,8 +41,8 @@ library MerkleLib { bool isRight = (indexAtHeight & 1) == 1; subtreeRoot = isRight - ? sha256(bytes.concat(_path[height], subtreeRoot)) - : sha256(bytes.concat(subtreeRoot, _path[height])); + ? Hash.sha256ToField(bytes.concat(_path[height], subtreeRoot)) + : Hash.sha256ToField(bytes.concat(subtreeRoot, _path[height])); /// @notice - We divide by two here to get the index of the parent of the current subtreeRoot in its own layer indexAtHeight >>= 1; } diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 82701303d25..587197b8088 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -177,7 +177,7 @@ library TxsDecoder { bytes.concat(vars.encryptedLogsHash, vars.unencryptedLogsHash) ); - vars.baseLeaves[i] = sha256(vars.baseLeaf); + vars.baseLeaves[i] = Hash.sha256ToField(vars.baseLeaf); } } @@ -235,14 +235,15 @@ library TxsDecoder { // Hash the logs of this iteration's function call bytes32 privateCircuitPublicInputsLogsHash = - sha256(slice(_body, offset, privateCircuitPublicInputLogsLength)); + Hash.sha256ToField(slice(_body, offset, privateCircuitPublicInputLogsLength)); offset += privateCircuitPublicInputLogsLength; // Decrease remaining logs length by this privateCircuitPublicInputsLogs's length (len(I?_LOGS)) and 4 bytes for I?_LOGS_LEN remainingLogsLength -= (privateCircuitPublicInputLogsLength + 0x4); - kernelPublicInputsLogsHash = - sha256(bytes.concat(kernelPublicInputsLogsHash, privateCircuitPublicInputsLogsHash)); + kernelPublicInputsLogsHash = Hash.sha256ToField( + bytes.concat(kernelPublicInputsLogsHash, privateCircuitPublicInputsLogsHash) + ); } return (kernelPublicInputsLogsHash, offset); @@ -267,7 +268,7 @@ library TxsDecoder { for (uint256 i = 0; i < treeDepth; i++) { for (uint256 j = 0; j < treeSize; j += 2) { - _leafs[j / 2] = sha256(bytes.concat(_leafs[j], _leafs[j + 1])); + _leafs[j / 2] = Hash.sha256ToField(bytes.concat(_leafs[j], _leafs[j + 1])); } treeSize /= 2; } diff --git a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol index c8a274816a5..cb2ee1f36af 100644 --- a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol +++ b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol @@ -2,8 +2,13 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; +import {Hash} from "../../libraries/Hash.sol"; import {IFrontier} from "../../interfaces/messagebridge/IFrontier.sol"; +// This truncates each hash and hash preimage to 31 bytes to follow Noir. +// It follows the logic in /noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr +// TODO(Miranda): Possibly nuke this contract, and use a generic version which can either use +// regular sha256 or sha256ToField when emulating circuits contract FrontierMerkle is IFrontier { uint256 public immutable HEIGHT; uint256 public immutable SIZE; @@ -22,7 +27,7 @@ contract FrontierMerkle is IFrontier { zeros[0] = bytes32(0); for (uint256 i = 1; i <= HEIGHT; i++) { - zeros[i] = sha256(bytes.concat(zeros[i - 1], zeros[i - 1])); + zeros[i] = Hash.sha256ToField(bytes.concat(zeros[i - 1], zeros[i - 1])); } } @@ -31,7 +36,7 @@ contract FrontierMerkle is IFrontier { uint256 level = _computeLevel(index); bytes32 right = _leaf; for (uint256 i = 0; i < level; i++) { - right = sha256(bytes.concat(frontier[i], right)); + right = Hash.sha256ToField(bytes.concat(frontier[i], bytes32(right))); } frontier[level] = right; @@ -65,9 +70,9 @@ contract FrontierMerkle is IFrontier { // and in that case we started higher up the tree revert("Mistakes were made"); } - temp = sha256(bytes.concat(frontier[i], temp)); + temp = Hash.sha256ToField(bytes.concat(frontier[i], temp)); } else { - temp = sha256(bytes.concat(temp, zeros[i])); + temp = Hash.sha256ToField(bytes.concat(temp, zeros[i])); } bits >>= 1; } diff --git a/l1-contracts/test/Parity.t.sol b/l1-contracts/test/Parity.t.sol index de14ded13f8..38221c75e66 100644 --- a/l1-contracts/test/Parity.t.sol +++ b/l1-contracts/test/Parity.t.sol @@ -12,11 +12,12 @@ contract ParityTest is Test { // Checks whether sha root matches output of base parity circuit function testRootMatchesBaseParity() public { - uint256[4] memory msgs = [ - 0x151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d78393537039, - 0x14c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e, - 0x1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a1, - 0x2806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e0 + // matches noir-protocol-circuits/crates/parity-lib/src/base/base_parity_inputs.nr + uint248[4] memory msgs = [ + 0x151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d783935370, + 0x14c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f, + 0x1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8, + 0x2806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1 ]; // We can't use Constants.NUM_MSGS_PER_BASE_PARITY directly when defining the array so we do the check here to @@ -39,21 +40,22 @@ contract ParityTest is Test { FrontierMerkle frontier = new FrontierMerkle(treeHeight); for (uint256 i = 0; i < msgs.length; i++) { - frontier.insertLeaf(bytes32(msgs[i])); + frontier.insertLeaf(bytes32(bytes.concat(new bytes(1), bytes31(msgs[i])))); } - bytes32 expectedRoot = 0xb3a3fc1968999f2c2d798b900bdf0de41311be2a4d20496a7e792a521fc8abac; + bytes32 expectedRoot = 0x00fc986d54a5e0af4f6e0d49399b9806c2b225e6c652fa5a831ecf6c6c29719d; assertEq(frontier.root(), expectedRoot, "Root does not match base parity circuit root"); } // Checks whether sha root matches output of root parity circuit function testRootMatchesRootParity() public { // sha256 roots coming out of base parity circuits - uint256[4] memory baseRoots = [ - 0xb3a3fc1968999f2c2d798b900bdf0de41311be2a4d20496a7e792a521fc8abac, - 0x43f78e0ebc9633ce336a8c086064d898c32fb5d7d6011f5427459c0b8d14e91f, - 0x024259b6404280addcc9319bc5a32c9a5d56af5c93b2f941fa326064fbe9636c, - 0x53042d820859d80c474d4694e03778f8dc0ac88fc1c3a97b4369c1096e904ae7 + // matches noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr + uint248[4] memory baseRoots = [ + 0xb3a3fc1968999f2c2d798b900bdf0de41311be2a4d20496a7e792a521fc8ab, + 0x43f78e0ebc9633ce336a8c086064d898c32fb5d7d6011f5427459c0b8d14e9, + 0x024259b6404280addcc9319bc5a32c9a5d56af5c93b2f941fa326064fbe963, + 0x53042d820859d80c474d4694e03778f8dc0ac88fc1c3a97b4369c1096e904a ]; // We can't use Constants.NUM_BASE_PARITY_PER_ROOT_PARITY directly when defining the array so we do the check here @@ -76,10 +78,10 @@ contract ParityTest is Test { FrontierMerkle frontier = new FrontierMerkle(treeHeight); for (uint256 i = 0; i < baseRoots.length; i++) { - frontier.insertLeaf(bytes32(baseRoots[i])); + frontier.insertLeaf(bytes32(bytes.concat(new bytes(1), bytes31(baseRoots[i])))); } - bytes32 expectedRoot = 0x8e7d8bf0ef7ebd1607cc7ff9f2fbacf4574ee5b692a5a5ac1e7b1594067b9049; + bytes32 expectedRoot = 0x00a0c56543aa73140e5ca27231eee3107bd4e11d62164feb411d77c9d9b2da47; assertEq(frontier.root(), expectedRoot, "Root does not match root parity circuit root"); } } diff --git a/l1-contracts/test/decoders/Decoders.t.sol b/l1-contracts/test/decoders/Decoders.t.sol index 162c402cea4..4fb7a90f212 100644 --- a/l1-contracts/test/decoders/Decoders.t.sol +++ b/l1-contracts/test/decoders/Decoders.t.sol @@ -170,10 +170,11 @@ contract DecodersTest is DecoderBase { (bytes32 logsHash, uint256 bytesAdvanced) = txsHelper.computeKernelLogsHash(encodedLogs); bytes32 kernelPublicInputsLogsHash = bytes32(0); - bytes32 privateCircuitPublicInputsLogsHash = sha256(new bytes(0)); + bytes32 privateCircuitPublicInputsLogsHash = Hash.sha256ToField(new bytes(0)); - bytes32 referenceLogsHash = - sha256(abi.encodePacked(kernelPublicInputsLogsHash, privateCircuitPublicInputsLogsHash)); + bytes32 referenceLogsHash = Hash.sha256ToField( + abi.encodePacked(kernelPublicInputsLogsHash, privateCircuitPublicInputsLogsHash) + ); assertEq(bytesAdvanced, encodedLogs.length, "Advanced by an incorrect number of bytes"); assertEq(logsHash, referenceLogsHash, "Incorrect logs hash"); @@ -191,9 +192,9 @@ contract DecodersTest is DecoderBase { // Zero because this is the first iteration bytes32 previousKernelPublicInputsLogsHash = bytes32(0); - bytes32 privateCircuitPublicInputsLogsHashFirstCall = sha256(firstFunctionCallLogs); + bytes32 privateCircuitPublicInputsLogsHashFirstCall = Hash.sha256ToField(firstFunctionCallLogs); - bytes32 referenceLogsHash = sha256( + bytes32 referenceLogsHash = Hash.sha256ToField( abi.encodePacked( previousKernelPublicInputsLogsHash, privateCircuitPublicInputsLogsHashFirstCall ) @@ -218,11 +219,12 @@ contract DecodersTest is DecoderBase { (bytes32 logsHash, uint256 bytesAdvanced) = txsHelper.computeKernelLogsHash(encodedLogs); bytes32 referenceLogsHashFromIteration1 = - sha256(abi.encodePacked(bytes32(0), sha256(firstFunctionCallLogs))); + Hash.sha256ToField(abi.encodePacked(bytes32(0), Hash.sha256ToField(firstFunctionCallLogs))); - bytes32 privateCircuitPublicInputsLogsHashSecondCall = sha256(secondFunctionCallLogs); + bytes32 privateCircuitPublicInputsLogsHashSecondCall = + Hash.sha256ToField(secondFunctionCallLogs); - bytes32 referenceLogsHashFromIteration2 = sha256( + bytes32 referenceLogsHashFromIteration2 = Hash.sha256ToField( abi.encodePacked( referenceLogsHashFromIteration1, privateCircuitPublicInputsLogsHashSecondCall ) @@ -255,19 +257,20 @@ contract DecodersTest is DecoderBase { (bytes32 logsHash, uint256 bytesAdvanced) = txsHelper.computeKernelLogsHash(encodedLogs); bytes32 referenceLogsHashFromIteration1 = - sha256(abi.encodePacked(bytes32(0), sha256(firstFunctionCallLogs))); + Hash.sha256ToField(abi.encodePacked(bytes32(0), Hash.sha256ToField(firstFunctionCallLogs))); - bytes32 privateCircuitPublicInputsLogsHashSecondCall = sha256(secondFunctionCallLogs); + bytes32 privateCircuitPublicInputsLogsHashSecondCall = + Hash.sha256ToField(secondFunctionCallLogs); - bytes32 referenceLogsHashFromIteration2 = sha256( + bytes32 referenceLogsHashFromIteration2 = Hash.sha256ToField( abi.encodePacked( referenceLogsHashFromIteration1, privateCircuitPublicInputsLogsHashSecondCall ) ); - bytes32 privateCircuitPublicInputsLogsHashThirdCall = sha256(thirdFunctionCallLogs); + bytes32 privateCircuitPublicInputsLogsHashThirdCall = Hash.sha256ToField(thirdFunctionCallLogs); - bytes32 referenceLogsHashFromIteration3 = sha256( + bytes32 referenceLogsHashFromIteration3 = Hash.sha256ToField( abi.encodePacked(referenceLogsHashFromIteration2, privateCircuitPublicInputsLogsHashThirdCall) ); diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 97af1e09f11..a862e82b53b 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -17,27 +17,27 @@ ] }, "block": { - "archive": "0x0209bb12c43db4a03ad5fb9eca8e49d58214896e8496e85836f02c2c4a2a6961", + "archive": "0x29598370fa40a50b7fbb99e501f11527a69e104a43c8eefbfe66888f137e7e49", "body": "0x0000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", + "txsEffectsHash": "0x008194e3dd375d5d878dcf9546bb5c2c77e165c6b1bef9aead8ceb35c3762bd5", "decodedHeader": { "contentCommitment": { - "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", - "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", + "outHash": "0x00efcbdb79553ae6863646bf36441755bc344a9a4af335fadc6659594faa4316", "txTreeHeight": 2, - "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc" + "txsEffectsHash": "0x008194e3dd375d5d878dcf9546bb5c2c77e165c6b1bef9aead8ceb35c3762bd5" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x64440eb664440eb664440eb664440eb664440eb6", - "feeRecipient": "0x2aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d" + "coinbase": "0x5e65711eaf5606f1f42dd36579261833e54595ee", + "feeRecipient": "0x00eafbad09eab548a89726e2a735bdcadc37aa4c318ed7a12d9be6a7542e517e" }, "lastArchive": { "nextAvailableLeafIndex": 1, - "root": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f" + "root": "0x1e3523d3bd50ae6204e1ec2ee1bdf8af4c6217ec80900052d2cf4259379dd130" }, "stateReference": { "l1ToL2MessageTree": { @@ -60,7 +60,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000064440eb664440eb664440eb664440eb664440eb62aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d", - "publicInputsHash": "0x02f561e8bd9cdbc88391e326f011ea90400b35260ac37bf525bf008638ebb5c3" + "header": "0x1e3523d3bd50ae6204e1ec2ee1bdf8af4c6217ec80900052d2cf4259379dd130000000010000000000000000000000000000000000000000000000000000000000000002008194e3dd375d5d878dcf9546bb5c2c77e165c6b1bef9aead8ceb35c3762bd500089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00efcbdb79553ae6863646bf36441755bc344a9a4af335fadc6659594faa43161864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000005e65711eaf5606f1f42dd36579261833e54595ee00eafbad09eab548a89726e2a735bdcadc37aa4c318ed7a12d9be6a7542e517e", + "publicInputsHash": "0x009e67eb54715bba61c94f475f6d4bf81b775da316c2c9a6a12506851f760bf0" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index bc8d58b5521..f6a627a00e6 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -17,27 +17,27 @@ ] }, "block": { - "archive": "0x068111eede1105ff5fb3e6fe24a67eb545e3ed15201936b805e72dfd21c9e611", + "archive": "0x045487d0ec498eb3f7f027715db8d67cc060604058bc5dd3e2e39fb47fe0ea17", "body": "0x0000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", + "txsEffectsHash": "0x008194e3dd375d5d878dcf9546bb5c2c77e165c6b1bef9aead8ceb35c3762bd5", "decodedHeader": { "contentCommitment": { - "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", - "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", + "outHash": "0x00efcbdb79553ae6863646bf36441755bc344a9a4af335fadc6659594faa4316", "txTreeHeight": 2, - "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc" + "txsEffectsHash": "0x008194e3dd375d5d878dcf9546bb5c2c77e165c6b1bef9aead8ceb35c3762bd5" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1711012048, + "timestamp": 1711036059, "version": 1, - "coinbase": "0x64440eb664440eb664440eb664440eb664440eb6", - "feeRecipient": "0x2aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d" + "coinbase": "0x5e65711eaf5606f1f42dd36579261833e54595ee", + "feeRecipient": "0x00eafbad09eab548a89726e2a735bdcadc37aa4c318ed7a12d9be6a7542e517e" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0209bb12c43db4a03ad5fb9eca8e49d58214896e8496e85836f02c2c4a2a6961" + "root": "0x29598370fa40a50b7fbb99e501f11527a69e104a43c8eefbfe66888f137e7e49" }, "stateReference": { "l1ToL2MessageTree": { @@ -60,7 +60,7 @@ } } }, - "header": "0x0209bb12c43db4a03ad5fb9eca8e49d58214896e8496e85836f02c2c4a2a6961000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065fbf8d064440eb664440eb664440eb664440eb664440eb62aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d", - "publicInputsHash": "0x0c14c3ec593635442b049dfe20c36cb9a303599acf4e4f836de5d45badbfd34a" + "header": "0x29598370fa40a50b7fbb99e501f11527a69e104a43c8eefbfe66888f137e7e49000000020000000000000000000000000000000000000000000000000000000000000002008194e3dd375d5d878dcf9546bb5c2c77e165c6b1bef9aead8ceb35c3762bd500089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00efcbdb79553ae6863646bf36441755bc344a9a4af335fadc6659594faa43161864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065fc569b5e65711eaf5606f1f42dd36579261833e54595ee00eafbad09eab548a89726e2a735bdcadc37aa4c318ed7a12d9be6a7542e517e", + "publicInputsHash": "0x00e9cfdd839060c90c216e1cecd24c5570a84e380e2bc640fd9dbbb5b2dd0718" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index c5fb7589f7c..d3b9839f52b 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,27 +34,27 @@ ] }, "block": { - "archive": "0x1e8e3ba20d7896997abf13f5f7e5a423fff51aba54c85ec8bd0c7eb18004252a", - "body": "0x0000000400380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b02185f8c0152162e19e296fff1a7e1664c5c8194faf05fc0450c5725c0de96009a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb60fbbab0f207b85446437daf4a753174801eee59e19f0c2203da8d4522de52b2c15a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb000000b008da11e3cf7794deddc5f101328b67834d6075f3fc13834dd109a4d54899a684aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6277412a5bc03576b5c24a1ad40e1c0c3b1bb2a8ae0b7b9fb01cefc5f589571a82d622c8b62e54bf51a1fd35b67456b229dae3bc6126977f1b2d88662a3418347000000b02092797a6aff6705d5b2b7b9cc1a10fefd2cbae0c2da7b28952fcce27349ed00ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb60ec82bc9765989689bc122af58ef11e23953872f2dc5414482132ed89345b82314b645af1d3b7df259bc545d7f52bc412546986a5f76ff3b331cb8dbddf1c9c20000021c000000b007e6929e25559903154f38bbe427621d84c517850fe802721573ff5badfa337bb23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb62680936011e15b8f93ade967f27dbb5de91fcc1bf48c391f463956e5bdf5fe9f2c6ead45b8c3501951a91b1618e165bcd512dd57263df715f742e0e908a2103e000000b01f9efa34c0dd6b2a0d3bff747db60b9934915c71d6aefa4cd99a2768d8aa79f7b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb60dd4ac83cc378d8cd34a6a6a0a8b0c7c70b828c04199c068c67d895ef8a6451a13c2c6697319821691459c1830eeb6db5cab39fb734b7e5f77871362435256b9000000b006f313587b339d274cd8807695c35cb7bc29b91623bc819659de59e2135ac072ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6258d141a67bf5fb3cb373122a419b5f820846dad0860b8438aa3b16c23568b962b7b2e000ea1543d893262d0ca7d60570c777ee83a12763a3bad3b6f6e029d350000021c000000b01eab7aef16bb6f4e44c5472f2f5206336bf5fe02ea8379711e0481ef3e0b06eebe3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb60ce12d3e221591b10ad3b224bc270716a81cca51556e3f8d0ae7e3e55e06d21112cf4723c8f7863ac8cee3d2e28ab175940fdb8c871ffd83bbf16de8a8b2e3b0000000b005ff9412d111a14b8461c831475f5751f38e5aa7379100ba9e48b46878bb4d69c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6249994d4bd9d63d802c078dd55b5b09257e90f3e1c353767cf0e0bf288b7188d2a87aeba647f5861c0bbaa8b7c195af143dc20794de6f55e801795f5d3632a2c000000b01db7fba96c9973727c4e8ee9e0ee00cda35a9f93fe57f895626edc75a36b93e5c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb60bedadf877f395d5425cf9df6dc301b0df816be26942beb14f523e6bc3675f0811dbc7de1ed58a5f00582b8d9426ac0fcb747d1d9af47ca8005bc86f0e1370a70000021c000000b0050c14cd26efa56fbbeb0febf8fb51ec2af2fc384b657fdee2b30eeede1bda60ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb623a6158f137b67fc3a49c0980751ab2c8f4db0cf3009b68c13786678ee17a58429942f74ba5d5c85f844f2462db5558b7b40c20a61bb7482c481f07c38c3b723000000b01cc47c63c2777796b3d7d6a49289fb67dabf4125122c77b9a6d936fc08cc20dcce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb60afa2eb2cdd199f979e6419a1f5efc4b16e60d737d173dd593bc98f228c7ebff10e8489874b38e8337e1734845c2a6aa02d91eaeaec8fbcc44c622f57373fd9e000000b0041895877ccda993f37457a6aa974c8662579dc95f39ff03271d6975437c6757d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb622b2964969596c2071d30852b8eda5c6c6b2526043de35b057e2c0ff5378327b28a0b02f103b60aa2fce3a00df515025b2a5639b758ff3a708ec4b029e24441a0000021c000000b01bd0fd1e18557bbaeb611e5f4425f6021223e2b62600f6ddeb4391826e2cadd3d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb60a06af6d23af9e1db16f8954d0faf6e54e4aaf0490ebbcf9d826f3788e2878f60ff4c952ca9192a76f6abb02f75ea1443a3dc03fc29d7af089307d7bd8d48a95000000b003251641d2abadb82afd9f615c33472099bc3f5a730e7e276b87c3fba8dcf44eda3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb621bf1703bf377044a95c500d6a89a060fe16f3f157b2b4d49c4d1b85b8d8bf7227ad30e9661964ce675781bb90ed4abfea0a052c896472cb4d56a5890384d111000000b01add7dd86e337fdf22ea6619f5c1f09c4988844739d576022fadec08d38d3acade3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb609133027798da241e8f8d10f8296f17f85af5095a4c03c1e1c914dfef38905ed0f014a0d206f96cba6f402bda8fa9bde71a261d0d671fa14cd9ad8023e35178c0000021c000000b0023196fc2889b1dc6286e71c0dcf41bad120e0eb86e2fd4baff21e820e3d8145e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb620cb97be15157468e0e597c81c259afb357b95826b8733f8e0b7760c1e394c6926b9b1a3bbf768f29ee0c9764289455a216ea6bd9d38f1ef91c1000f68e55e08000000b019e9fe92c41184035a73add4a75deb3680ed25d84da9f5267418468f38edc7c1e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6081fb0e1cf6ba666208218ca3432ec19bd13f226b894bb4260fba88558e992e40e0dcac7764d9aefde7d4a785a969678a9070361ea46793912053288a395a483000000b0013e17b67e67b6009a102ed6bf6b3c550885827c9ab77c6ff45c7908739e0e3cea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb61fd818786af3788d186edf82cdc195956ce037137f5bb31d2521d0928399d96025c6325e11d56d16d66a1130f4253ff458d3484eb10d7113d62b5a95ce45eaff0000021c000000b018f67f4d19ef882791fcf58f58f9e5d0b851c769617e744ab882a1159e4e54b8ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6072c319c2549aa8a580b6084e5cee6b3f47893b7cc693a66a566030bbe4a1fdb0d1a4b81cc2b9f14160692330c329112e06ba4f2fe1af85d566f8d0f08f6317a000000b0004a9870d445ba24d1997691710736ef3fea240dae8bfb9438c6d38ed8fe9b33f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb61ee49932c0d17cb14ff8273d7f5d902fa444d8a493303241698c2b18e8fa665724d2b31867b3713b0df358eba5c13a8e9037e9dfc4e1f0381a95b51c33a677f6000000b0180300076fcd8c4bc9863d4a0a95e06aefb668fa7552f36efcecfb9c03aee1aff63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb60638b2567b27aeae8f94a83f976ae14e2bdd3548e03db98ae9d05d9223aaacd20c26cc3c2209a3384d8fd9edbdce8bad17d0468411ef77819ad9e7956e56be710000021c000000b02fbb679e0b555e72c1730402a42489e69f82ade73c19eb49c11323a92e5f282bfa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb61df119ed16af80d587816ef830f98ac9dba97a35a704b165adf6859f4e5af34e23df33d2bd91755f457ca0a6575d3528c79c8b70d8b66f5c5f000fa2990704ed000000b0170f80c1c5ab9070010f8504bc31db05271b0a8b8927729341575622690f6ea6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb605453310d105b2d2c71deffa4906dbe86341d6d9f41238af2e3ab818890b39c90b334cf677e7a75c851921a86f6a86474f34e81525c3f6a5df44421bd3b74b68000000b02f2f726e313bed8aa817744c75f83f026d46d3220cf60ab935b9df6608e8c253023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb61d6524bd3c960fed6e25df4202cd3fe5a96d9f7077e0d0d5229d415c28e48d7623533ea2e37804772c2110f02930ea449560b0aba9928ecbd3a6cb5f73909f1500000fa400000168000000b016838b91eb921f87e7b3f54e8e059020f4df2fc65a039202b5fe11df439908ce063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb604b93de0f6ec41eaadc260441ada91043105fc14c4ee581ea2e173d56394d3f10aa757c69dce36746bbd91f2413e3b631cf90d4ff6a0161553eafdd8ae40e590000000b02e3bf3288719f1aedfa0bc072794399ca4ab74b320ca89dd7a2439ec6e494f4a0a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb61c71a57792741411a5af26fcb4693a7fe0d241018bb54ff967079be28e451a6d225fbf5d3956089b63aa58aadacce4deccc5523cbd670df0181125e5d8f12c0c00000168000000b015900c4c417023ac1f3d3d093fa18abb2c43d1576dd81126fa686c65a8f995c50e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb603c5be9b4cca460ee54ba7fecc768b9e686a9da5d8c2d742e74bce5bc8f560e809b3d880f3ac3a98a346d9acf2da35fd545daee10a7495399855585f13a17287000000b02d4873e2dcf7f5d3172a03c1d9303436dc101644349f0901be8e9472d3a9dc41123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb61b7e2631e8521835dd386eb76605351a1836e2929f89cf1dab71f668f3a5a764216c40178f340cbf9b33a0658c68df790429f3cdd13b8d145c7b806c3e51b90300000168000000b0149c8d06974e27d056c684c3f13d855563a872e881ac904b3ed2c6ec0e5a22bc163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb602d23f55a2a84a331cd4efb97e1286389fcf3f36ec9756672bb628e22e55eddf08c0593b498a3ebcdad02167a47630978bc250721e49145ddcbfb2e57901ff7e000000b02c54f49d32d5f9f74eb34b7c8acc2ed11374b7d54873882602f8eef9390a69381a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a8aa6ec3e301c5a14c1b67217a12fb44f9b8423b35e4e41efdc50ef5906345b2078c0d1e51210e3d2bce8203e04da133b8e955ee5100c38a0e5daf2a3b245fa00000168000000b013a90dc0ed2c2bf48e4fcc7ea2d97fef9b0d147995810f6f833d217273baafb31e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb601dec00ff8864e57545e37742fae80d2d733e0c8006bd58b7020836893b67ad607ccd9f59f6842e11259692256122b31c326f203321d9382212a0d6bde628c75000000b02b61755788b3fe1b863c93373c68296b4ad959665c48074a4763497f9e6af62f223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6199727a6940e207e4c4afe2cc93d2a4e870025b4c732cd663446ab75be66c1521f85418c3af015080a462fdaefa0d4ad72f336eff8e48b5ce55035790912d2f100000168000000b012b58e7b430a3018c5d9143954757a89d271b60aa9558e93c7a77bf8d91b3caa263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb600eb40ca4e64527b8be77f2ee14a7b6d0e988259144054afb48addeef91707cd06d95aaff546470549e2b0dd07ae25cbfa8b939445f212a6659467f243c3196c000000b02a6df611de92023fbdc5daf1ee042405823dfaf7701c866e8bcda40603cb83262a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb618a3a860e9ec24a283d445e77ad924e8be64c745db074c8a78b105fc23c74e491e91c24690ce192c41cf7795a13ccf47aa57d8810cb90a8129ba8fff6e735fe800000168000000b011c20f3598e8343cfd625bf40611752409d6579bbd2a0db80c11d67f3e7bc9a12e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb6305c0ff78573f6c97bc10ca01467ce646e310c32a1ce44653cd72e094e7794c505e5db6a4b244b29816bf897b94a206631f0352559c691caa9fec278a923a663000000b0297a76cc34700663f54f22ac9fa01e9fb9a29c8883f10592d037fe8c692c101d323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb617b0291b3fca28c6bb5d8da22c751f82f5c968d6eedbcbaebd1b60828927db401d9e4300e6ac1d507958bf5052d8c9e1e1bc7a12208d89a56e24ea85d3d3ecdf00000168000000b010ce8fefeec6386134eba3aeb7ad6fbe413af92cd0fe8cdc507c3105a3dc5698363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb62f6890b1db51faedb34a545ac603c8fea595adc3b5a2c3898141888fb3d821bc04f25c24a1024f4db8f540526ae61b006954d6b66d9b10eeee691cff0e84335a000000b02886f7868a4e0a882cd86a67513c1939f1073e1997c584b714a25912ce8c9d143a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb616bca9d595a82ceaf2e6d55cde111a1d2d2e0a6802b04ad30185bb08ee8868371caac3bb3c8a2174b0e2070b0474c47c19211ba3346208c9b28f450c393479d600000168000000b00fdb10aa44a43c856c74eb6969496a58789f9abde4d30c0094e68b8c093ce38f3e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb62e75116c312fff11ead39c15779fc398dcfa4f54c97742adc5abe3161938aeb303fedcdef6e05371f07e880d1c82159aa0b97847816f901332d3778573e4c051000000b027937840e02c0eac6461b22202d813d4286bdfaaab9a03db590cb39933ed2a0b423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb615c92a8feb86310f2a701d178fad14b76492abf91684c9f745f0158f53e8f52e1bb7447592682598e86b4ec5b610bf165085bd34483687edf6f99f929e9506cd00000168000000b00ee791649a8240a9a3fe33241ae564f2b0043c4ef8a78b24d950e6126e9d7086463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb62d819226870e0336225ce3d0293bbe33145ef0e5dd4bc1d20a163d9c7e993baa030b5d994cbe57962807cfc7ce1e1034d81e19d895440f37773dd20bd9454d48000000b0269ff8fb360a12d09beaf9dcb4740e6e5fd0813bbf6e82ff9d770e1f994db7024a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb614d5ab4a4164353361f964d241490f519bf74d8a2a59491b8a5a7015b94982251ac3c52fe84629bd1ff4968067acb9b087ea5ec55c0b07123b63fa1903f593c400000168000000b00df4121ef06044cddb877adecc815f8ce768dde00c7c0a491dbb4098d3fdfd7d4e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb62c8e12e0dcec075a59e62b8adad7b8cd4bc39276f12040f64e809822e3f9c8a10217de53a29c5bba5f9117827fba0acf0f82bb69a9188e5bbba82c923ea5da3f000000b025ac79b58be816f4d374419766100908973522ccd3430223e1e168a5feae43f9523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb613e22c04974239579982ac8cf2e509ebd35bef1b3e2dc83fcec4ca9c1eaa0f1c19d045ea3e242de1577dde3b1948b44abf4f00566fdf86367fce549f695620bb00000168000000b00d0092d9463e48f21310c2997e1d5a271ecd7f712050896d62259b1f395e8a74563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb62b9a939b32ca0b7e916f73458c73b3678328340804f4c01a92eaf2a9495a559801245f0df87a5fde971a5f3d3156056946e75cfabced0d8000128718a4066736000000b024b8fa6fe1c61b190afd895217ac03a2ce99c45de7178148264bc32c640ed0f05a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb612eeacbeed203d7bd10bf447a48104860ac090ac52024764132f2522840a9c1318dcc6a4940232058f0725f5cae4aee4f6b3a1e783b4055ac438af25ceb6adb200380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b00c0d13939c1c4d164a9a0a542fb954c15632210234250891a68ff5a59ebf176b5e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb62aa7145588a80fa2c8f8bb003e0fae01ba8cd59918c93f3ed7554d2faebae28f0030dfc84e586402cea3a6f7e2f200037e4bfe8bd0c18ca4447ce19f0966f42d000000b023c57b2a37a41f3d4286d10cc947fe3d05fe65eefaec006c6ab61db2c96f5de7623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb611fb2d7942fe41a008953c02561cff204225323d65d6c68857997fa8e96b290a17e9475ee9e03629c6906db07c80a97f2e1843789788847f08a309ac34173aa9000000b00b19944df1fa513a8223520ee1554f5b8d96c29347f987b5eafa502c041fa462663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb629b3950fde8613c7008202baefaba89bf1f1772a2c9dbe631bbfa7b6141b6f862fa1aef585680850be7d3469160f52fadde488655e4f7c59ccc931b95ec781250000021c000000b022d1fbe48d8223617a1018c77ae3f8d73d6307800ec07f90af2078392ecfeade6a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb61107ae3398dc45c4401e83bd07b8f9ba7989d3ce79ab45ac9c03da2f4ecbb60116f5c8193fbe3a4dfe19b56b2e1ca419657ce509ab5d03a34d0d64329977c7a0000000b00a26150847d8555eb9ac99c992f149f5c4fb64245bce06da2f64aab2698031596e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb628c015ca346417eb380b4a75a147a336295618bb40723d87602a023c797bfc7d2eae2fafdb460c74f6067c23c7ab4d95154929f67223fb7e11338c3fc4280e1c000000b021de7c9ee3602785b19960822c7ff37174c7a9112294feb4f38ad2bf943077d5723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb610142eedeeba49e877a7cb77b954f454b0ee755f8d7fc4d0e06e34b5b42c42f8160248d3959c3e7235a2fd25dfb89eb39ce1869abf3182c79177beb8fed854970000021c000000b0093295c29db65982f135e184448d448ffc6005b56fa285fe73cf0538cee0be50763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb627cc96848a421c0f6f94923052e39dd060baba4c5446bcaba4945cc2dedc89742dbab06a312410992d8fc3de7947482f4cadcb8785f87aa2559de6c629889b13000000b020eafd59393e2ba9e922a83cde1bee0bac2c4aa236697dd937f52d45f99104cc7a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb60f20afa844984e0caf3113326af0eeeee85316f0a15443f524d88f3c198ccfef150ec98deb7a42966d2c44e09154994dd446282bd30601ebd5e2193f6438e18e000000b0083f167cf3945da728bf293ef6293f2a33c4a74683770522b8395fbf34414b477e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb626d9173ee0202033a71dd9eb047f986a981f5bdd681b3bcfe8feb749443d166b2cc73124870214bd65190b992ae342c984126d1899ccf9c69a08414c8ee9280a0000021c000000b01ff77e138f1c2fce20abeff78fb7e8a5e390ec334a3dfcfd7c5f87cc5ef191c3823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb60e2d30629a765230e6ba5aed1c8ce9891fb7b881b528c3196942e9c27eed5ce6141b4a48415846baa4b58c9b42f093e80baac9bce6da81101a4c73c5c9996e85000000b0074b9737497261cb604870f9a7c539c46b2948d7974b8446fca3ba4599a1d83e863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb625e597f935fe2457dea721a5b61b9304cf83fd6e7befbaf42d6911cfa99da3622bd3b1dedce018e19ca25353dc7f3d63bb770ea9ada178eade729bd2f449b501000000b01f03fecde4fa33f2583537b24153e3401af58dc45e127c21c0c9e252c4521eba8a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb60d39b11cf05456551e43a2a7ce28e423571c5a12c8fd423dadad4448e44de9dd1327cb0297364adedc3ed455f48c8e82430f6b4dfaaf00345eb6ce4c2ef9fb7c0000021c000000b0065817f19f5065ef97d1b8b45961345ea28dea68ab20036b410e14cbff0265358e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb624f218b38bdc287c1630696067b78d9f06e89eff8fc43a1871d36c560efe30592ae0329932be1d05d42b9b0e8e1b37fdf2dbb03ac175f80f22dcf65959aa41f8000000b01e107f883ad838168fbe7f6cf2efddda525a2f5571e6fb4605343cd929b2abb1923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb60c4631d746325a7955ccea627fc4debd8e80fba3dcd1c161f2179ecf49ae76d412344bbced144f0313c81c10a628891c7a740cdf0e837f58a32128d2945a8873000000b0056498abf52e6a13cf5b006f0afd2ef8d9f28bf9bef4828f85786f526462f22c963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb623fe996de1ba2ca04db9b11b195388393e4d4090a398b93cb63dc6dc745ebd5029ecb353889c212a0bb4e2c93fb732982a4051cbd54a7733674750dfbf0aceef0000021c000000b01d1d004290b63c3ac747c727a48bd87489bed0e685bb7a6a499e975f8f1338a89a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb60b52b2919c105e9d8d56321d3160d957c5e59d34f0a640863681f955af0f03cb1140cc7742f253274b5163cb57c483b6b1d8ae702257fe7ce78b8358f9bb156a000000b0047119664b0c6e3806e44829bc99299311572d8ad2c901b3c9e2c9d8c9c37f239e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb6230b1a28379830c48542f8d5caef82d375b1e221b76d3860faa82162d9bf4a4728f9340dde7a254e433e2a83f1532d3261a4f35ce91ef657abb1ab66246b5be6000000b01c2980fce694405efed10ee25627d30ec1237277998ff98e8e08f1e5f473c59fa23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb60a5f334bf1ee62c1c4df79d7e2fcd3f1fd4a3ec6047abfaa7aec53dc146f90c2104d4d3198d0574b82daab8609607e50e93d5001362c7da12bf5dddf5f1ba2610000021c000000b0037d9a20a0ea725c3e6d8fe46e35242d48bbcf1be69d80d80e4d245f2f240c1aa63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb622179ae28d7634e8bccc40907c8b7d6dad1683b2cb41b7853f127be93f1fd73e2805b4c8345829727ac7723ea2ef27cc990994edfcf3757bf01c05ec89cbe8dd000000b01b3601b73c724483365a569d07c3cda8f8881408ad6478b2d2734c6c59d45296aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6096bb40647cc66e5fc68c1929498ce8c34aee057184f3ecebf56ae6279d01db90f59cdebeeae5b6fba63f340bafc78eb20a1f1924a00fcc570603865c47c2f58000000b0028a1adaf6c8768075f6d79f1fd11ec7802070acfa71fffc52b77ee594849911ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb621241b9ce354390cf455884b2e277807e47b2543df1636a9837cd66fa4806435271235828a362d96b250b9f9548b2266d06e367f10c7f4a034866072ef2c75d40000021c000000b01a428271925048a76de39e57b95fc8432fecb599c138f7d716dda6f2bf34df8db23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6087834c09daa6b0a33f2094d4634c9266c1381e82c23bdf303c108e8df30aab00e664ea6448c5f93f1ed3afb6c987385580693235dd57be9b4ca92ec29dcbc4f000000b001969b954ca67aa4ad801f59d16d1961b785123e0e467f209721d96bf9e52608b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb620309c5739323d312bded005dfc372a21bdfc6d4f2eab5cdc7e730f609e0f12c261eb63ce01431bae9da01b406271d0107d2d810249c73c478f0baf9548d02cb000000b0194f032be82e4ccba56ce6126afbc2dd6751572ad50d76fb5b48017924956c84ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb60784b57af3886f2e6b7b5107f7d0c3c0a37823793ff83d17482b636f449137a70d72cf609a6a63b8297682b61e346e1f8f6b34b471a9fb0df934ed728f3d494600000fa400000168000000b000a31c4fa2847ec8e5096714830913fbeee9b3cf221afe44db8c33f25f45b2ffbe3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb61f3d1d118f104155636817c0915f6d3c5344686606bf34f20c518b7c6f417e23252b36f735f235df2163496eb7c3179b3f3779a13870f2e8bd5b157fb9ed8fc2000000b0185b83e63e0c50efdcf62dcd1c97bd779eb5f8bbe8e1f61f9fb25bff89f5f97bc23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb60691363549667352a30498c2a96cbe5adadcc50a53ccbc3b8c95bdf5a9f1c49e0c7f501af04867dc60ffca70cfd068b9c6cfd645857e7a323d9f47f8f49dd63d00000168000000b03013eb7cd9942316d4e2f485b62666f34e823da8afa8edfa63d8840cb4a63ff7c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb61e499dcbe4ee45799af15f7b42fb67d68aa909f71a93b41650bbe602d4a20b1a2437b7b18bd03a0358ec9129695f1235769c1b324c45720d01c570061f4e1cb9000000b0176804a093ea5514147f7587ce33b811d61a9a4cfcb67543e41cb685ef568672ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6059db6ef9f447776da8de07d5b08b8f51241669b67a13b5fd100187c0f5251950b8bd0d546266c009889122b816c6353fe3477d69952f9568209a27f59fe633400000168000000b02f206c372f72273b0c6c3c4067c2618d85e6df39c37d6d1ea842de931a06cceece3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb61d561e863acc499dd27aa735f4976270c20dab882e68333a952640893a0298112344386be1ae3e279075d8e41afb0ccfae00bcc36019f131462fca8c84aea9b0000000b01674855ae9c859384c08bd427fcfb2ac0d7f3bde108af4682887110c54b71369d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb604aa37a9f5227b9b121728380ca4b38f49a6082c7b75ba84156a730274b2de8c0a98518f9c047024d01259e633085dee35991967ad27787ac673fd05bf5ef02b00000168000000b02e2cecf185502b5f43f583fb195e5c27bd4b80cad751ec42ecad39197f6759e5d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb61c629f4090aa4dc20a03eef0a6335d0af9724d19423cb25ed9909b0f9f6325082250b926378c424bc7ff209ecc970769e5655e5473ee70558a9a2512ea0f36a7000000b0158106153fa65d5c839204fd316bad4644e3dd6f245f738c6cf16b92ba17a060da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb603b6b8644b007fbf49a06ff2be40ae29810aa9bd8f4a39a859d4cd88da136b8309a4d249f1e27449079ba1a0e4a458886cfdbaf8c0fbf79f0ade578c24bf7d2200000168000000b02d396dabdb2e2f837b7ecbb5cafa56c1f4b0225beb266b673117939fe4c7e6dcde3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb61b6f1ffae68851e6418d36ab57cf57a530d6eeaa561131831dfaf59604c3b1ff215d39e08d6a466fff8868597e3302041cc9ffe587c2ef79cf047f994f6fc39e000000b0148d86cf95846180bb1b4cb7e307a7e07c487f003833f2b0b15bc6191f782d57e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb602c3391ea0de83e38129b7ad6fdca8c3b86f4b4ea31eb8cc9e3f280f3f73f87a08b1530447c0786d3f24e95b96405322a4625c89d4d076c34f48b2128a200a1900000168000000b02c45ee66310c33a7b30813707c96515c2c14c3ecfefaea8b7581ee264a2873d3e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb61a7ba0b53c66560a79167e66096b523f683b903b69e5b0a76265501c6a243ef62069ba9ae3484a943711b0142fcefc9e542ea1769b976e9e136eda1fb4d05095000000b0139a0789eb6265a4f2a4947294a3a27ab3ad20914c0871d4f5c6209f84d8ba4eea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb601cfb9d8f6bc8807b8b2ff682178a35defd3ecdfb6f337f0e2a98295a4d4857107bdd3be9d9e7c9176ae311647dc4dbcdbc6fe1ae8a4f5e793b30c98ef80971000000168000000b02b526f2086ea37cbea915b2b2e324bf66379657e12cf69afb9ec48acaf8900caee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb61988216f92445a2eb09fc620bb074cd99fa031cc7dba2fcba6cfaaa2cf84cbed1f763b5539264eb86e9af7cee16af7388b934307af6bedc257d934a61a30dd8c000000b012a68844414069c92a2ddc2d463f9d14eb11c2225fdcf0f93a307b25ea394745f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb600dc3a934c9a8c2bf03c4722d3149df827388e70cac7b7152713dd1c0a35126806ca5478f37c80b5ae3778d0f9784857132b9fabfc79750bd81d671f54e1240700000168000000b02a5eefdadcc83bf0221aa2e5dfce46909ade070f26a3e8d3fe56a33314e98dc1f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb61894a229e8225e52e8290ddb6ca34773d704d35d918eaeefeb3a052934e558e41e82bc0f8f0452dca6243f899306f1d2c2f7e498c3406ce69c438f2c7f916a83000000b011b308fe971e6ded61b723e7f7db97af227663b373b1701d7e9ad5ac4f99d43cfa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6304d09c083aa3079e015d4940631f0ef86d1184a5855a6caaf602d365f959f6005d6d533495a84d9e5c0c08bab1442f14a90413d104df4301c87c1a5ba41b0fe00000168000000b0296b709532a6401459a3eaa0916a412ad242a8a03a7867f842c0fdb97a4a1ab8fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb617a122e43e0062771fb255961e3f420e0e6974eea5632e142fa45faf9a45e5db1d8f3cc9e4e25700ddad874444a2ec6cfa5c8629d714ec0ae0ade9b2e4f1f77a000000b0112713cebd04fd05485b9431c9af4ccaf03a88ee448d8f8cf34191692a236e6402400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb62fc11490a990bf91c6ba44ddd805a60b54953d852931c63a2406e8f33a1f3988054ae0036f4113f1cc6530d57ce7f80d18546677e12a139f912e7d6294cb4b2600000168000000b028df7b65588ccf2c40485aea633df646a006cddb0b548767b767b97654d3b4e006400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb617152db463e6f18f0656c5dff012f729dc2d9a29763f4d83a44b1b6c74cf80031d03479a0ac8e618c451f78e1676a188c820ab64a7f10b7a5554a56fbf7b91a2000000b01033948912e301297fe4dbec7b4b4765279f2a7f58620eb137abebef8f83fb5b0a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb62ecd954aff6ec3b5fe438c9889a1a0a58bf9df163d06455e687143799f7fc67f045760bdc51f181603ee78902e83f2a74fb90808f4fe92c3d598d7e8fa2bd81d00000168000000b027ebfc1fae6ad35077d1a2a514d9f0e0d76b6f6c1f29068bfbd213fcba3441d70e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb61621ae6eb9c4f5b33de00d9aa1aef1c413923bba8a13cca7e8b575f2da300cfa1c0fc85460a6ea3cfbdb3f48c8129c22ff854cf5bbc58a9e99befff624dc1e99000000b00f40154368c1054db76e23a72ce741ff5f03cc106c368dd57c164675f4e4885212400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb62dda1605554cc7da35ccd4533b3d9b3fc35e80a750dac482acdb9e0004e053760363e1781afd1c3a3b77c04ae01fed41871da99a08d311e81a03326f5f8c6514003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b026f87cda0448d774af5aea5fc675eb7b0ed010fd32fd85b0403c6e831f94cece16400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb6152e2f290fa2f9d775695555534aec5e4af6dd4b9de84bcc2d1fd0793f9099f11b1c490eb684ee613364870379ae96bd36e9ee86cf9a09c2de295a7c8a3cab90000000b00e4c95fdbe9f0971eef76b61de833c9996686da1800b0cf9c080a0fc5a4515491a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb62ce696bfab2acbfe6d561c0decd995d9fac3223864af43a6f145f8866a40e06d0270623270db205e7301080591bbe7dbbe824b2b1ca7910c5e6d8cf5c4ecf20b000000b02604fd945a26db98e6e4321a7811e6154634b28e46d204d484a6c90984f55bc51e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb6143aafe36580fdfbacf29d1004e6e6f8825b7edcb1bccaf0718a2affa4f126e81a28c9c90c62f2856aedcebe2b4a91576e4e9017e36e88e72293b502ef9d38870000021c000000b00d5916b8147d0d962680b31c901f3733cdcd0f3293df8c1e04eafb82bfa5a24022400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb62bf3177a0108d022a4df63c89e7590743227c3c97883c2cb35b0530ccfa16d64017ce2ecc6b92482aa8a4fc04357e275f5e6ecbc307c1030a2d7e77c2a4d7f02000000b025117e4eb004dfbd1e6d79d529ade0af7d99541f5aa683f8c911238fea55e8bc26400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb61347309dbb5f021fe47be4cab682e192b9c0206dc5914a14b5f485860a51b3df19354a836240f6a9a2771678dce68bf1a5b331a8f743080b66fe0f8954fdc57e000000b00c6597726a5b11ba5e09fad741bb31ce0531b0c3a7b40b424955560925062f372a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62aff983456e6d446dc68ab8350118b0e698c655a8c5841ef7a1aad933501fa5b008963a71c9728a6e213977af4f3dd102d4b8e4d44508f54e74242028fae0bf90000021c000000b0241dff0905e2e3e155f6c18fdb49db49b4fdf5b06e7b031d0d7b7e164fb675b32e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb61253b158113d06441c052c85681edc2cf124c1fed965c938fa5ee00c6fb240d61841cb3db81efacdda005e338e82868bdd17d33a0b17872fab686a0fba5e5275000000b00b72182cc03915de95934291f3572c683c965254bb888a668dbfb08f8a66bc2e32400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb62a0c18eeacc4d86b13f1f33e01ad85a8a0f106eba02cc113be8508199a6287522ffa32d453a6ccf4d1ed24ec281130078ce41826d1de7f0a6f8e921ce50e98f1000000b0232a7fc35bc0e8058d80094a8ce5d5e3ec629741824f824151e5d89cb51702aa36400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb611603212671b0a68538e744019bad6c72889638fed3a485d3ec93a92d512cdcd174e4bf80dfcfef21189a5ee401e8126147c74cb1eec0653efd2c4961fbedf6c0000021c000000b00a7e98e716171a02cd1c8a4ca4f3270273faf3e5cf5d098ad22a0b15efc749253a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb6291899a902a2dc8f4b7b3af8b3498042d855a87cb401403802ef629fffc314492f06b38ea984d11909766ca6d9ad2aa1c448b9b7e5b2fe2eb3f8eca34a6f25e8000000b02237007db19eec29c50951053e81d07e23c738d296240165965033231a778fa13e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb6106cb2ccbcf90e8c8b17bbfacb56d1615fee0521010ec781833395193a735ac4165accb263db03164912eda8f1ba7bc04be1165c32c08578343d1f1c851f6c63000000b0098b19a16bf51e2704a5d207568f219cab5f9576e33188af1694659c5527d61c42400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb628251a635880e0b3830482b364e57add0fba4a0dc7d5bf5c4759bd266523a1402e133448ff62d53d40ffb4618b49253bfbad5b48f9877d52f8634729afcfb2df0000021c000000b021438138077cf04dfc9298bff01dcb185b2bda63a9f88089daba8da97fd81c9846400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb60f79338712d712b0c2a103b57cf2cbfb9752a6b214e346a5c79def9f9fd3e7bb15674d6cb9b9073a809c3563a356765a8345b7ed4695049c78a779a2ea7ff95a000000b008979a5bc1d3224b3c2f19c2082b1c36e2c43707f70607d35afec022ba8863134a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb627319b1dae5ee4d7ba8dca6e16817577471eeb9edbaa3e808bc417acca842e372d1fb5035540d9617888fc1c3ce51fd63311fcda0d5bfc773ccda1b015303fd6000000b0205001f25d5af472341be07aa1b9c5b292907bf4bdccffae1f24e82fe538a98f4e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb60e85b44168b516d4fa2a4b702e8ec695ceb7484328b7c5ca0c084a26053474b21473ce270f970b5eb8257d1e54f270f4baaa597e5a6983c0bd11d4294fe086510000021c000000b007a41b1617b1266f73b8617cb9c716d11a28d8990ada86f79f691aa91fe8f00a52400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb6263e1bd8043ce8fbf2171228c81d70117e838d2fef7ebda4d02e72332fe4bb2e2c2c35bdab1edd85b01243d6ee811a706a769e6b21307b9b8137fc367a90cccd000000b01f5c82acb338f8966ba528355355c04cc9f51d85d1a17ed2638f42b64a99368656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb60d9234fbbe931af931b3932ae02ac130061be9d43c8c44ee5072a4ac6a9501a913804ee165750f82efaec4d9068e6b8ef20efb0f6e3e02e5017c2eafb5411348000000b006b09bd06d8f2a93ab41a9376b63116b518d7a2a1eaf061be3d3752f85497d015a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb6254a9c925a1aed2029a059e379b96aabb5e82ec103533cc91498ccb9954548252b38b67800fce1a9e79b8b91a01d150aa1db3ffc3504fabfc5a256bcdff159c40000021c000000b01e6903670916fcbaa32e6ff004f1bae70159bf16e575fdf6a7f99d3caff9c37d5e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb60c9eb5b614711f1d693cdae591c6bbca3d808b655060c41294dcff32cff58ea0128ccf9bbb5313a727380c93b82a662929739ca08212820945e689361aa1a03f000000b005bd1c8ac36d2eb7e2caf0f21cff0c0588f21bbb32838540283dcfb5eaaa09f862400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb624571d4caff8f1446129a19e2b556545ed4cd0521727bbed5903273ffaa5d51c2a45373256dae5ce1f24d34c51b90fa4d93fe18d48d979e40a0cb1434551e6bb000000b01d7584215ef500dedab7b7aab68db58138be60a7f94a7d1aec63f7c3155a507466400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb60bab36706a4f2341a0c622a04362b66474e52cf664354336d94759b935561b9711995056113117cb5ec1544e69c660c360d83e3195e7012d8a50e3bc80022d360000021c000000b004c99d45194b32dc1a5438acce9b069fc056bd4c465804646ca82a3c500a96ef6a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb623639e0705d6f56898b2e958dcf15fe024b171e32afc3b119d6d81c6600662132951b7ecacb8e9f256ae1b0703550a3f10a4831e5cadf9084e770bc9aab273b2000000b01c8204dbb4d305031240ff656829b01b702302390d1efc3f30ce52497abadd6b6e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb60ab7b72ac02d2765d84f6a5af4feb0feac49ce877809c25b1db1b43f9ab6a88e10a5d110670f1bef964a9c091b625b5d983cdfc2a9bb8051cebb3e42e562ba2d000000b003d61dff6f29370051dd806780370139f7bb5edd5a2c8388b11284c2b56b23e672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb622701ec15bb4f98cd03c31138e8d5a7a5c1613743ed0ba35e1d7dc4cc566ef0a285e38a70296ee168e3762c1b4f104d9480924af7082782c92e16650101300a900000fa400000168000000b01b8e85960ab1092749ca472019c5aab5a787a3ca20f37b637538accfe01b6a6276400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb609c437e5160b2b8a0fd8b215a69aab98e3ae70188bde417f621c0ec6001735850fb251cabced2013cdd3e3c3ccfe55f7cfa18153bd8fff76132598c94ac34724000000b002e29eb9c5073b248966c82231d2fbd42f20006e6e0102acf57cdf491acbb0dd7a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb6217c9f7bb192fdb107c578ce40295514937ab50552a5395a264236d32ac77c01276ab9615874f23ac5c0aa7c668cff737f6dc6408456f750d74bc0d675738da000000168000000b01a9b0650608f0d4b81538edacb61a54fdeec455b34c7fa87b9a30756457bf7597e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb608d0b89f6be92fae4761f9d05836a6331b1311a99fb2c0a3a686694c6577c27c0ebed28512cb2438055d2b7e7e9a5092070622e4d1647e9a578ff34fb023d41b000000b001ef1f741ae53f48c0f00fdce36ef66e6684a1ff81d581d139e739cf802c3dd482400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb620892036077101d53f4ec088f1c54faecadf56966679b87e6aac9159902808f826773a1bae52f65efd49f2371828fa0db6d267d1982b76751bb61b5cdad41a9700000168000000b019a7870ab66d116fb8dcd6957cfd9fea1650e6ec489c79abfe0d61dcaadc845086400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb607dd3959c1c733d27eeb418b09d2a0cd5277b33ab3873fc7eaf0c3d2cad84f730dcb533f68a9285c3ce6733930364b2c3e6ac475e538fdbe9bfa4dd615846112000000b000fba02e70c3436cf8795797950af1089de9439095aa00f57e519455e58ccacb8a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb61f95a0f05d4f05f976d80843a3614a490243f8277a4e37a2af16ebdff58895ef2583bad60430fa8334d339f1c9c4f4a7ee370962abfff599602075e34034a78e00000168000000b018b407c50c4b1593f0661e502e999a844db5887d5c70f8d04277bc63103d11478e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb606e9ba1417a537f6b6748945bb6e9b6789dc54cbc75bbeec2f5b1e593038dc6a0cd7d3f9be872c80746fbaf3e1d245c675cf6606f90d7ce2e064a85c7ae4ee09000000b0000820e8c6a1479130029f5246a6eba2d54de521a97e8019c2bbeedc4aed57c292400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb61ea221aab32d0a1dae614ffe54fd44e339a899b88e22b6c6f38146665ae922e624903b905a0efea76c5c81ac7b60ef42259baaf3bfd474bda48ad069a595348500000168000000b017c0887f622919b827ef660ae035951e851a2a0e704577f486e216e9759d9e3e96400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb605f63ace6d833c1aedfdd1006d0a9601c140f65cdb303e1073c578df959969610be454b4146530a4abf902ae936e4060ad3407980ce1fc0724cf02e2e0457b00000000b02f78f015fdb0ebdf1fdc2cc379c43e9a34e66efb370c6fcf4b083ef6a04de4ba9a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb61daea265090b0e41e5ea97b906993f7d710d3b49a1f735eb37eba0ecc049afdd239cbc4aafed02cba3e5c9672cfce9dc5d004c84d3a8f3e1e8f52af00af5c17c00000168000000b016cd0939b8071ddc5f78adc591d18fb8bc7ecb9f8419f718cb4c716fdafe2b359e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb60502bb88c361403f258718bb1ea6909bf8a597edef04bd34b82fd365faf9f6580af0d56e6a4334c8e3824a69450a3afae498a92920b67b2b69395d6945a607f7000000b02e8570d0538ef0035765747e2b6039346c4b108c4ae0eef38f72997d05ae71b1a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb61cbb231f5ee912661d73df73b8353a17a871dcdab5cbb50f7c55fb7325aa3cd422a93d0505cb06efdb6f1121de98e4769464ee15e77d73062d5f857670564e7300000168000000b015d989f40de522009701f580436d8a52f3e36d3097ee763d0fb6cbf6405eb82ca6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6040f3c43193f44635d106075d0428b36300a397f02d93c58fc9a2dec605a834f09fd5628c02138ed1b0b9223f6a635951bfd4aba348afa4fada3b7efab0694ee000000b02d91f18aa96cf4278eeebc38dcfc33cea3afb21d5eb56e17d3dcf4036b0efea8aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb61bc7a3d9b4c7168a54fd272e69d134b1dfd67e6bc9a03433c0c055f98b0ac9cb21b5bdbf5ba90b1412f858dc9034df10cbc98fa6fb51f22a71c9dffcd5b6db6a00000168000000b014e60aae63c32624ce8b3d3af50984ed2b480ec1abc2f5615421267ca5bf4523ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6031bbcfd6f1d48879499a83081de85d0676edb1016adbb7d41048872c5bb10460909d6e315ff3d115294d9dea842302f5361ec4b485f7973f20e1276106721e5000000b02c9e7244ff4af84bc67803f38e982e68db1453ae7289ed3c18474e89d06f8b9fb2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb61ad424940aa51aae8c866ee91b6d2f4c173b1ffcdd74b358052ab07ff06b56c220c23e79b1870f384a81a09741d0d9ab032e31380f26714eb6343a833b17686100000168000000b013f28b68b9a12a49061484f5a6a57f8762acb052bf977485988b81030b1fd21ab6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb602283db7c4fb4cabcc22efeb337a806a9ed37ca12a823aa1856ee2f92b1b9d3d0816579d6bdd41358a1e219959de2ac98ac68ddc5c33f89836786cfc75c7aedc000000b02baaf2ff5528fc6ffe014bae403429031278f53f865e6c605cb1a91035d01896ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb619e0a54e60831ed2c40fb6a3cd0929e64e9fc18df149327c49950b0655cbe3b91fcebf340765135c820ae851f36cd4453a92d2c922faf072fa9e9509a077f55800000168000000b012ff0c230f7f2e6d3d9dccb058417a219a1151e3d36bf3a9dcf5db8970805f11be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb60134be721ad950d003ac37a5e5167b04d6381e323e56b9c5c9d93d7f907c2a340722d857c1bb4559c1a769540b7a2563c22b2f6d700877bc7ae2c782db283bd3000000b02ab773b9ab070094358a9368f1d0239d49dd96d09a32eb84a11c03969b30a58dc2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb618ed2608b66122f6fb98fe5e7ea524808604631f051db1a08dff658cbb2c70b01edb3fee5d431780b994300ca508cedf71f7745a36cf6f973f08ef9005d8824f00000168000000b0120b8cdd655d32917527146b09dd74bbd175f374e74072ce2160360fd5e0ec08c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb600413f2c70b754f43b357f6096b2759f0d9cbfc3522b38ea0e439805f5dcb72b062f59121799497df930b10ebd161ffdf98fd0fe83dcf6e0bf4d22094088c8ca000000b029c3f47400e504b86d13db23a36c1e3781423861ae076aa8e5865e1d00913284ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb617f9a6c30c3f271b3322461930411f1abd6904b018f230c4d269c013208cfda71de7c0a8b3211ba4f11d77c756a4c979a95c15eb4aa3eebb83734a166b390f4600380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b011180d97bb3b36b5acb05c25bb796f5608da9505fb14f1f265ca90963b4178ffce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb62fb20e59a7c6f9422b0f0cd1c9cfc8966d35499cdfb9289f968fe8204b3d4423053bd9cc6d774da230b9f8c96eb21a9830f4728f97b1760503b77c8fa5e955c1000000b028d0752e56c308dca49d22de550818d1b8a6d9f2c1dbe9cd29f0b8a365f1bf7bd2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb61706277d621d2b3f6aab8dd3e1dd19b4f4cda6412cc6afe916d41a9985ed8a9e1cf4416308ff1fc928a6bf820840c413e0c0b77c5e786ddfc7dda49cd0999c3d000000b010248e5211193ad9e439a3e06d1569f0403f36970ee97116aa34eb1ca0a205f6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb62ebe8f13fda4fd666298548c7b6bc330a499eb2df38da7c3dafa42a6b09dd11a04485a86c35551c668434084204e153268591420ab85f5294821d7160b49e2b80000021c000000b027dcf5e8aca10d00dc266a9906a4136bf00b7b83d5b068f16e5b1329cb524c72da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb61612a837b7fb2f63a234d58e9379144f2c3247d2409b2f0d5b3e751feb4e17951c00c21d5edd23ed6030073cb9dcbeae1825590d724ced040c47ff2335fa2934000000b00f310f0c66f73efe1bc2eb9b1eb1648a77a3d82822bdf03aee9f45a3060292edde400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb62dcb0fce5383018a9a219c472d07bdcadbfe8cbf076226e81f649d2d15fe5e110354db41193355ea9fcc883ed1ea0fcc9fbdb5b1bf5a744d8c8c319c70aa6faf000000b026e976a3027f112513afb253b8400e0627701d14e984e815b2c56db030b2d969e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6151f28f20dd93387d9be1d4945150ee96396e963546fae319fa8cfa650aea48c1b0d42d7b4bb281197b94ef76b78b9484f89fa9e86216c2850b259a99b5ab62b0000021c000000b00e3d8fc6bcd54322534c3355d04d5f24af0879b936926f5f3309a0296b631fe4e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb62cd79088a96105aed1aae401dea3b86513632e501b36a60c63cef7b37b5eeb0802615bfb6f115a0ed755cff983860a66d7225742d32ef371d0f68c22d60afca6000000b025f5f75d585d15494b38fa0e69dc08a05ed4bea5fd596739f72fc83696136660ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6142ba9ac63b737ac11476503f6b109839afb8af468442d55e4132a2cb60f31831a19c3920a992c35cf4296b21d14b3e286ee9c2f99f5eb4c951cb43000bb4322000000b00d4a108112b347468ad57b1081e959bee66d1b4a4a66ee837773faafd0c3acdbee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb62be41142ff3f09d309342bbc903fb2ff4ac7cfe12f0b2530a8395239e0bf77ff016ddcb5c4ef5e330edf17b4352205010e86f8d3e70372961560e6a93b6b899d0000021c000000b025027817ae3b196d82c241c91b78033a96396037112de65e3b9a22bcfb73f357f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb613382a66b9953bd048d0acbea84d041dd2602c857c18ac7a287d84b31b6fbe7a1926444c6077305a06cbde6cceb0ae7cbe533dc0adca6a70d9870eb6661bd019000000b00c56913b68914b6ac25ec2cb338554591dd1bcdb5e3b6da7bbde5536362439d2f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb62af091fd551d0df740bd737741dbad99822c717242dfa454eca3acc0462004f6007a5d701acd625746685f6ee6bdff9b45eb9a64fad7f1ba59cb412fa0cc1694000000b0240ef8d204191d91ba4b8983cd13fdd4cd9e01c82502658280047d4360d4804efa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb61244ab210f733ff48059f47959e8feb809c4ce168fed2b9e6ce7df3980d04b711832c506b655347e3e552627804ca916f5b7df51c19ee9951df1693ccb7c5d100000021c000000b00b6311f5be6f4f8ef9e80a85e5214ef355365e6c720feccc0048afbc9b84c6c9fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb629fd12b7aafb121b7846bb31f377a833b991130356b42379310e0746ab8091ed2feb2c9d51dd06a53641ece019db5292a584243e8865e16fe2179149f62ca38c000000b0238303a229ffaca9a0eff9cd9ee7b2f09b622702f5de84f1f4ab39003b5e1a7602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb611b8b5f13559cf0c66fe64c32bbcb3d3d788f35160c94b0de18e9af65b59e59917a6cfd6dc3bc39624f9967152205e32c37c048c927b0904929824f9a605f738000000b00ad71cc5e455dea6e08c7acfb6f5040f22fa83a742ec0c3b74ef6b79760e60f106410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb629711d87d0e1a1335eeb2b7bc54b5d4f8755383e279042e8a5b4c303860a2c152f5f376d77c395bd1ce65d29ebaf07ae73484979594200df56be4d06d0b63db40000021c000000b0228f845c7fddb0cdd87941885083ad8ad2c6c89409b3041639159386a0bea76d0a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb610c536ab8b37d3309e87ac7ddd58ae6e0eed94e2749dca3225f8f57cc0ba729016b350913219c7ba5c82de2c03bc58ccfae0a61da64f8828d7027f800b66842f000000b009e39d803a33e2cb1815c28a6890fea95a5f253856c08b5fb959c5ffdb6eede80e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb6287d9e4226bfa5579674733676e757e9beb9d9cf3b64c20cea1f1d89eb6ab90c2e6bb827cda199e1546fa4e49d4b0248aaaceb0a6d1680039b28a78d3616caab000000b0219c0516d5bbb4f210028943021fa8250a2b6a251d87833a7d7fee0d061f346412410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb60fd1b765e115d754d610f4388ef4a90846523673887249566a635003261aff8715bfd14b87f7cbde940c25e6b5585367324547aeba24074d1b6cda0670c711260000021c000000b008f01e3a9011e6ef4f9f0a451a2cf94391c3c6c96a950a83fdc4208640cf7adf16410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb6278a1efc7c9da97bcdfdbaf128835283f61e7b604f3941312e89781050cb46032d7838e2237f9e058bf8ec9f4ee6fce2e2118c9b80eaff27df9302139b7757a2000000b020a885d12b99b916478bd0fdb3bba2bf41900bb6315c025ec1ea48936b7fc15b1a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb60ede382036f3db790d9a3bf34090a3a27db6d8049c46c87aaecdaa898b7b8c7e14cc5205ddd5d002cb956da166f44e0169a9e93fcdf886715fd7348cd6279e1d000000b007fc9ef4e5efeb13872851ffcbc8f3ddc928685a7e6989a8422e7b0ca63007d61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb626969fb6d27bada0058702abda1f4d1e2d831cf1630dc05572f3d296b62bd2fa2c84b99c795da229c382345a0082f77d19762e2c94bf7e4c23fd5c9a00d7e4990000021c000000b01fb5068b8177bd3a7f1518b865579d5978f4ad47453081830654a319d0e04e5222410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb60deab8da8cd1df9d452383adf22c9e3cb51b7995b01b479ef338050ff0dc197513d8d2c033b3d427031eb55c1890489ba10e8ad0e1cd0595a4418f133b882b14000000b007091faf3bcdef37beb199ba7d64ee78008d09eb923e08cc8698d5930b9094cd26410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb625a320712859b1c43d104a668bbb47b864e7be8276e23f79b75e2d1d1b8c5ff12b913a56cf3ba64dfb0b7c14b21ef21750dacfbda893fd706867b72066387190000000b01ec18745d755c15eb69e607316f397f3b0594ed8590500a74abefda03640db492a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb60cf73994e2afe3c17caccb68a3c898d6ec801b26c3efc6c337a25f96563ca66c12e5537a8991d84b3aa7fd16ca2c4335d8732c61f5a184b9e8abe999a0e8b80b00000fa400000168000000b00615a06991abf35bf63ae1752f00e91237f1ab7ca61287f0cb03301970f121c42e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb624afa12b7e37b5e8749992213d5742529c4c60138ab6be9dfbc887a380ecece82a9dbb112519aa723294c3cf63baecb1883f714ebc687c94acd211a6cb98fe87000000b01dce08002d33c582ee27a82dc88f928de7bdf0696cd97fcb8f2958269ba1684032410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb60c03ba4f388de7e5b43613235564937123e4bcb7d7c445e77c0cba1cbb9d336311f1d434df6fdc6f723144d17bc83dd00fd7cdf3097603de2d1644200649450200000168000000b005222123e789f7802dc4292fe09ce3ac6f564d0db9e707150f6d8a9fd651aebb36410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb623bc21e5d415ba0cac22d9dbeef33cecd3b101a49e8b3dc24032e229e64d79df29aa3bcb7af7ae966a1e0b8a1556e74bbfa412dfd03cfbb8f13c6c2d30f98b7e000000b01cda88ba8311c9a725b0efe87a2b8d281f2291fa80adfeefd393b2ad0101f5373a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb60b103b098e6bec09ebbf5ade07008e0b5b495e48eb98c50bc07714a320fdc05a10fe54ef354de093a9ba8c8c2d64386a473c6f841d4a830271809ea66ba9d1f900000168000000b0042ea1de3d67fba4654d70ea9238de46a6baee9ecdbb863953d7e5263bb23bb23e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb622c8a2a029f3be30e3ac2196a08f37870b15a335b25fbce6849d3cb04bae06d628b6bc85d0d5b2baa1a75344c6f2e1e5f708b470e4117add35a6c6b3965a1875000000b01be70974d8efcdcb5d3a37a32bc787c25687338b94827e1417fe0d336662822e42410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb60a1cbbc3e449f02e2348a298b89c88a592adffd9ff6d443004e16f29865e4d51100ad5a98b2be4b7e143d446df0033047ea11115311f0226b5eaf92cd10a5ef000000168000000b0033b22989345ffc89cd6b8a543d4d8e0de1f902fe190055d98423faca112c8a946410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb621d5235a7fd1c2551b356951522b3221427a44c6c6343c0ac9079736b10e93cd27c33d4026b3b6ded9309aff788edc802e6d5601f7e5fa017a112139fbbaa56c000000b01af38a2f2ecdd1ef94c37f5ddd63825c8debd51ca856fd385c6867b9cbc30f254a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb609293c7e3a27f4525ad1ea536a38833fca12a16b1341c354494bc9afebbeda480f175663e109e8dc18cd1c01909c2d9eb605b2a644f3814afa5553b3366aebe700000168000000b00247a352e92403ecd460005ff570d37b158431c0f5648481dcac9a33067355a04e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb620e1a414d5afc67952beb10c03c72cbb79dee657da08bb2f0d71f1bd166f20c426cfbdfa7c91bb0310b9e2ba2a2ad71a65d1f7930bba7925be7b7bc0611b3263000000b01a000ae984abd613cc4cc7188eff7cf6c55076adbc2b7c5ca0d2c24031239c1c52410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb60835bd389005f876925b320e1bd47dda017742fc271642788db62436511f673f0e23d71e36e7ed00505663bc42382838ed6a543758c8006f3ebfae399bcb78de00000168000000b00154240d3f0208110be9481aa70cce154ce8d352093903a62116f4b96bd3e29756410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb61fee24cf2b8dca9d8a47f8c6b5632755b14387e8eddd3a5351dc4c437bcfadbb25dc3eb4d26fbf2748432a74dbc6d1b49d3699241f8ef84a02e5d646c67bbf5a000000b0190c8ba3da89da3803d60ed3409b7790fcb5183ecffffb80e53d1cc6968429135a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb607423df2e5e3fc9ac9e479c8cd70787438dbe48d3aeac19cd2207ebcb67ff4360d3057d88cc5f12487dfab76f3d422d324cef5c86c9c7f93832a08c0012c05d500000168000000b00060a4c794e00c3543728fd558a8c8af844d74e31d0d82ca65814f3fd1346f8e5e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb61efaa589816bcec1c1d1408166ff21efe8a8297a01b1b9779646a6c9e1303ab224e8bf6f284dc34b7fcc722f8d62cc4ed49b3ab53363776e475030cd2bdc4c51000000b018190c5e3067de5c3b5f568df237722b3419b9cfe3d47aa529a7774cfbe4b60a62410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb6064ebead3bc200bf016dc1837f0c730e7040861e4ebf40c1168ad9431be0812d0c3cd892e2a3f548bf68f331a5701d6d5c3397598070feb7c7946346668c92cc00000168000000b02fd173f4cbefb083334c1d468bc61ba6e3e5febcaa9b727fedcd9f5a2694fc8666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb61e072643d749d2e5f95a883c189b1c8a200ccb0b1586389bdab101504690c7a923f540297e2bc76fb755b9ea3efec6e90bffdc464737f6928bba8b53913cd948000000b017258d188645e28072e89e48a3d36cc56b7e5b60f7a8f9c96e11d1d3614543016a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb6055b3f6791a004e338f7093e30a86da8a7a527af6293bfe55af533c981410e240b49594d3881f96cf6f23aec570c1807939838ea94457ddc0bfebdcccbed1fc300000168000000b02eddf4af21cdb4a76ad565013d6216411b4aa04dbe6ff1a43237f9e08bf5897d6e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb61d13a6fe2d27d70a30e3cff6ca37172457716c9c295ab7c01f1b5bd6abf154a02301c0e3d409cb93eedf01a4f09ac18343647dd75b0c75b6d024e5d9f69d663f000000b016320dd2dc23e6a4aa71e603556f675fa2e2fcf20b7d78edb27c2c59c6a5cff872410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb60467c021e77e0907708050f8e2446842df09c94076683f099f5f8e4fe6a19b1b0a55da078e5ffd912e7b82a708a812a1cafcda7ba819fd0050691853314dacba00000168000000b02dea756977abb8cba25eacbbeefe10db52af41ded24470c876a25466f156167476410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb61c2027b88305db2e686d17b17bd311be8ed60e2d3d2f36e46385b65d1151e197220e419e29e7cfb82668495fa236bc1d7ac91f686ee0f4db148f40605bfdf336000000b0153e8e8d3201eac8e1fb2dbe070b61f9da479e831f51f811f6e686e02c065cef7a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb6037440dc3d5c0d2ba80998b393e062dd166e6ad18a3cbe2de3c9e8d64c02281209625ac1e43e01b56604ca61ba440d3c02617c0cbbee7c2494d372d996ae39b100000168000000b02cf6f623cd89bcefd9e7f476a09a0b758a13e36fe618efecbb0caeed56b6a36b7e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb61b2ca872d8e3df529ff65f6c2d6f0c58c63aafbe5103b608a7f010e376b26e8e211ac2587fc5d3dc5df1911a53d2b6b7b22dc0f982b573ff58f99ae6c15e802d000000b0144b0f4787dfeeed19847578b8a75c9411ac4014332677363b50e1669166e9e682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb60280c196933a114fdf92e06e457c5d774dd30c629e113d522834435cb162b509086edb7c3a1c05d99d8e121c6be007d639c61d9dcfc2fb48d93dcd5ffc0ec6a8", - "txsEffectsHash": "0x72973218cc03166a5ea58f3b9a3ee51ddc7c73afca1d69e0db36abffe6ed00f8", + "archive": "0x1ddfa79462a8e2beea5cca8199d5ce0f9b0412d561d4a35c8905b8e8b2beb7ca", + "body": "0x0000000400380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b010a2bbd74d570162c997959bacb8696740c7e546d1e820a3ef3cbb06aec5b2dbe4ff56246431b95bca6a9f2b2292fde63c6d78884aae32a500f0152abc901ee282de062d3415d375de3593c40b6e14f06b0c6df665794962b73019e11d7a0c04127bd70a45136ea8b9ae21a8ed4c970111c8064d017f5b0f2c5393737cfeb206e38a47b1bf58417e605c97c4349d9b8f15e8b51b7fba8cb1e31cc6fabff0392b27cf7c1dfec5d9b20db8af3a38e9f903000000b01c7a7c90871d4f3bbdc115e923409bf63575c0f12ed1861b1d48f634642d15c62e5814361b1e0d5200248cc389944d91e9980efd0d6db6debd331eb0cfae4528048770f423e0871b5f5874535d207787bc4a55b85692ed99b4edcc4522ac7f2d1c186d3504b5976902405d03ec5cee862d0e0ce317ffa4c69ab4e04c335603c576df0e1f2b1c63c874146baf0cb7c476030f3a511054686e095db2f3c7cd3542e9849f287bcbf895dedfdfaeb0652226000000b01605c3d4b8545cbcf35ad088aa62cbcb872f0d8c62acc490de9005135e51fd7cab21c962dcc1abe65f28e96adcd271a6c1a238940e1aed0257f6e3576526c8f626da07e617f3afaeb40bb364e2005c3b58970aba95ae52fc917f3991478ad83e93f399158cb773aa4171e14f63faf9901cf8003377010e084f7e2a251f3421f5d84b6ec9f80eb89388ca2c6b0dbd3fb91bf7ecf4b536467c2890704bd416c9663a11753f21d820f99678f910a0b270600000021c000000b01121aedf25d06480c417ca7cb9e27e1fbc5f938585e775a81739a7ec767d5ce5a8a3f3e0e4e467cc0ea34c07ce4db5d68fef8565e828794928633d171fb83005070a8a4709998b3a5814daf9c2c11153ad50e38eb130e34dfaf33aa5988ef1dc8ecc4d3356b3e7b845b5afa54348e40e1e2c30d28d219431b8faf8133d00c868f13e7c7d465aaf3155ead482557510c606662ec826720642271ed4efd0a7fe0c257dc13f0accbc5224a1d9015f4391a7000000b00318659a0573453a083b2a2845123900f7bc8454cb63792438f4e2a11439801c6c1bc432909789212410d5d44d45f93193b28bf7fbc6aa8e1a9268fe1c93bcf63fc5f64603cbb7955eb77ce99d31208ba624775cd64b9853414ec95e764176bb219b9aeef74685bf2594ae9bfbf7660f0eb5a1bb11ec4a60e38c0bd52426ecdb3058c00f35d08a43f8ef19a68c58da0a2223e984f661613b2064d2741693290290e52cc71bad840884c0bab1cfce0a52000000b00ff2c077e06b3fac309ad0df3fae04b6899da0c2e043e99014661995c34552f83c9d20b274bac94336446fc3a63128f174891456eb6b4bb053f32b66a736d66ca18cb1dc3695b451c07031b0e9a09482400f6691109a41666e4024f1b3d5f99e11bf51dfc94e7a19802d73eff6d2f86d15840b1a0238fdb01febe6e89a7cef8d1f54e6ce24d64c471d0b166555d58be6244464a816a380382f67269d26a0f70b0a50c157a3d023580620a156a020a87f0000021c000000b003c33d4fdff90f92b4f450012410cb1fa23c82cf72f4fcf1dc574bebedde6272df862c312cd18ea78ddd5d1446e46beeb93a9123176ed56456523edd813cb6ae96d7aa33d1dea51f19107c120d9edc98da74175f444b47532b45fb084bbde002d93b5b7c36391c948f43c59869ecc48024880a809f6137e609dcbb1de15f05a22aa43528016823ff3b6f5921afc7ff301f086609a1c1a7704b7b1c80ef0074d6eed2a8075e0f72652bbd16b8f50a4862000000b0242984b0585a5096a968fa461f07592ade773e3c0071ba6bd143fdbce81a8a7b17d8e5161e2bc1d2bc806de06d226d8650e19fc4279217c3f96b8fadaf841748c966ae395e4c0cda32a6b008b11a80aafdb088e1d62f13e7270595e7200ed98f21ae7ed0060a32ff3521d98772ad0bc024af543dc6a2b5267727de64242273e4a2cb09f2c109a4a258f8cd74ee38abda15073c7a51cc5ae3512548438681a4aede6c7016b2cfcc03d8a35c20f529acb2000000b0006652e8552e21b361b4160b36e7ac116778a553a0927e7fc55b283461bd93346ca3efa5bf58ad80fb16555c83c2694631c66878c8a3528f01fd1f746e0d90b407874e8f7a487617347ee8d730ce1687c28dffffda2519b61b9a169dd4dd627f7e785c2a4ee3d199c04a1b164a618b6d04ea0f7bcc62131af5419f3df44166e4adcac0b4e5217199228817dee2d4f28d1236f0c8a83b6c8d8d735cdd9c6f7cf492ce5cf433b388daa3e26ca2405d9c010000021c000000b0052d908ec0b2e9cd6e5628cc8e243ca5530a17f0aa18db85148408c172e33a92ec4138ec6aa2ea646030d71709c5f1b1190cf9b003eb13b580c23d8bda08838b4eb76dc00a4f6b63f39a0c60029cd02ca17bb0d63fb5da3d4bab157620855863fcfc22270e4f45cd1e2ba8e301e6d5fa0801a8b87145d47f31d504fa83ffefc1f07f6c0a75b76c55a47d50b9b2673d962524bd859638116314320ad833903e5b30173ce12bffbd1ff446914d8404200f000000b0299c4fd95291aca6e748e82827210766579fb0ffde0197fccae53515ae463719244bffee25fe480a8be6c6d3e2c31fa702a7f3c647ee94727af63109b529fa138b34b2d5addeb3ea9934edb4589743885601b8a9be5c4f4ab5422637355898acd8adc7a2b88c5c73bc5807384593834114c87e48a29986223c5b368376e74b5d1242c655f852d9d7bfdef3ab428225252518bd83500fb934f106a22d485d86cb9f6418abc3ecd48b9f0819c4c0060010000000b01c6845e9d28419318fd5e797c1f8d88ecf30097b811a99f423eb41fb6995f8712dff65dcabac4bbcd0be157fcb4b081922c27d4d2d300d525d06bb30672a36c379106ef440f9e525c12f359d9f0b096c45a21609630fd717bbf13b23796d2b9ec83c0271e1eba2026bf1565dacef55ab26c18cce82323b5bbd3cd5cc4367804cbe55308b13e5774c5a07f520315bb8080da0f0582e10fd05f50fbcca6cb0c11df1fa8c727d2dd157f90bd451fe965c800000021c000000b0031f6b8e470850aa720fc25fa5f306b6e08b47dd5b8e14aca4589c54261105fe7d6cc9de0b279259489cc824b796f59d1dc1bcaf45b947c3a1c3a48e0fda61479a394faed65c2920c95205293a5d09a08013781e4d5252826982c93bd5851b51dea2d6638145a86dd4dd5766e5e1c38d0879e36a685203a58cf1cffcc59c45aca7240484e4bda347b3a6626c76afedee211cbebe42d72693319db999a827d635f81c29872e92f2d97195f2a107dcec1a000000b00248161253bb0b33afc7c842ffcde325c99f22956ccf70ab1099249251a8a1c029b8613953dc14d5cff2a8aa62a9a2994ba4b9e0a3402ca35f0bc9d83bcd8da9b3d02051f596c601e73a6e1a26935284a4a017408cd7079a80e6bda684163a2fa3b0486c9048a4de95442eb90535dfca146a6bb89f6904179472b1ecafa518c5a3407a6e4e7c83e7262f18a8f0bd7588239020a8381abb877817935e185b8185f2835c49c89274ca7c2de8ccdbee6fc1000000b023be9f5b3e9360a9b1c581ea18005151eefaa0719e8ec3f0b515e1eab2ee81ee9f915c0088e833b98507bb1671be2ef312b26b155ca9094088270ee1be17f961de1183a8c5d0cb5eabe98bd986110a6b90e26b6db7d6767c64011c842591f13820f2188c63bdd2edbc91c5d9c6a29bae240c3fbc165b03c27574c8784209b9ba94741ddd483207c9eeb3eb5a1ad448f20febae533801e0c96f8cd92724dd8649fa62fb1bea3104b5dc99330ae23f45830000021c000000b01bf9a2c02ffe30760952f802c32979c0daaed35fa4260f810c203f0abca95a277ca6fb6b1b882e977add7b3a333e3d5d95edcafa5d9771c51ceb6a226af31b836737e8f98f3dfc5388f7ed15c58dc6d11f56173d177332f33901fdd03f0b8157921f530bdfac446a306178ec146797bd27b9da853b34ddee295b5c8047104604373ae066458303dc4c91e3eac4286c241c99a421bf7f23b7ccb1713e4446e8fe67a4ac22aa31bfcb023732cfb6bc4453000000b0018792b500e03b5c6bb98d6d86be7a9a3b9f7a4ea4318def4dfef60a93d8d6ab8a8f1dd680b93693c8e94804a3430a30401f7af77787cee1abf78bdc996488bbfc31f5295d2c0beab5b91f5fccafbdbe93c94da31f5842a1283b09a816de65307cfae755042cacfeb9e6f9aeb67e40910d72d0aa34555a205f4302bb9916e6dfdbfd7be5f49068e03f5f80c78bbd5de90dcbad85f1cb4ad472ed8cdb47048bb7a0bd7484011169bc7956344547e8c103000000b02bc9148b852422f4871f768344e0fd3609be9d568574bbff431fd273786d81187f2dbc7827c9b93805ee2b94c035a8ae37af5f1163e93a6b9a15b6cc39f55ece9f0f680f5981b603526c511264cc1db27104330fbb427c84264c72700c3cc4a21325b71f07762b6891a9b323e26b798d12a823137549a0f6024be9989b2823556ad277090f81c80bacc977108fd9641e3003eecde2afae9a0f9fa9ff0ccff022251116c1dd193b64749e74fe9a42fe260000021c000000b02580633868ce13e1655567dc358400c3f99e4147e58559ef132f3a72e8e9ac6c8d91dfc3ef61b2616e1ef389a768f33199527adbfe5a06b18fb1dd1f62e8e964539c5c264a7b3d290b4e13d33a9d24e401e17564cc3c1951dfb3e0122ececc2972adf20b0ed3d4db6ee1a23473d0c64710fd83f9bec67f9cf884606a05d811e62fb4850e7ced3ab0e9375b6588500f422f81806e5e2e6e7c5021782acfc667aafb1841afe433f8ecd91836c90800ed30000000b0107b6e87ad40e85b3f5ba72bae59666b665ee468ab8e71982b31c2acb61abf1cfeaff5bed71428ab3ece6553b6143c2d9b2cca7ff6dc465c87ad77885d82da1886225f68612f91479512326053cde3f97349f01b38b0fcc9d4bb4a95c0e9a4db1aa5f44d9f9b2007fd65a22bca383e8b28648b5e1f8240c7c5932e2d8e074d49a9d8049bc3ae47bd424f75fcff2123c61ea170c3853af3d3b9fd3f43891c9ad27458cf173af644bb4dc295a0dac5b443000000b0254f07678ef9f49650c2f8d0bfd424b5786169fcf7fa29d3521b5efe6c50b21603ac7c1cb2a2a28e4a7e03021be330f69bd6848e1ed60279bd6c5600a189411aa6270a27c0e5ea618cfda0692a30fe7777fabef5297b7455a29e1d30bdf3429deedd7b1e000810ae87cfe53db454556c079033549d009304fdbb5e284379ee92e783460722aec1583e0662fd3836746c01c89a966397ab7312e1f634a8ae30c5888553092031d0e5cb2010147678ed0b0000021c000000b00c0b165f1fbf39d9aa5e6e548c0f578423049ab1f2634122730061ce256f9df914fff081e93aa4ce2ba047111b3f74208657ffcc96f360639fa071ceb8db88f59d06cd57d23ff2a272b9c52711cf80a181f0d3be2a66487414d4e6a58f106c3efbccab1d69befa7ea0af8a177ede1f7e16ae171e0e0e5b29d39832d5bac3d3a87bdcf77128226a03dff68668f19e31a1148eb2f219a7d7628e92b1e8a9c99b70b577dbfe8f4b2e339dbe379ea778fa50000000b02891f68d0b2d696b9a18b42af098be0d4ae8356372866177a6ad3745bd36fd9b0437d47adc6d91b1baa9975e9c797ce5f65cc8bf08d70eba1074f2a81d078493ca8d15a6cb77dd3931de19b8f32206e5a006a51a2e9890051d1e71eebce96f30f4dd2176c9b3d5d02dd9f6af12c514042b85d4a05d7793feb4d115712c14669a9759cfba28232fa354e6cdc25886f179243c6331efa97c33e03fbb418ccb1c1b20ae117530e4fc7e899c2ea8503ef3bc000000b013618eab09b8b2c8cc4d3a00404d34b1ba3d23060b667ceca197ff0908ff5df5037a78e17199e8742ab759a08acfffb3fb1ab564a5f7e932a30bccb36ce67b8c0ec53e76ab1c9f90cc82870fad281e2343a24c9bcff8ad4559d884e1bd64c4ce2d5320375e5ac096c0ac042d620664901d0e8211d7aff0e85972071091d17f71d874de464a290cdbb304d466efdaeea5123efc8178fef3ab873fba8c9f83f9e287bc1ca15409cd4f33172c0176e2399900000fa400000168000000b012a5537385fada7cb844d388e08d82ad69692a507f910bf48101120f36da01613a91c0af94cb3292707d1acb3504efc034ee838db52e1de62aff10273e66827c49b0357ccbd236d816620389733be5693755909628c4f6b0d9e0c28582c167dd04705755fb112a88b778ab6e051e13491ff60dcd01ea47508dd4fc804530c41b0b82459420451dac741225fe708b768d1ae51aecea986276d20ec31465965ad0061477d010137a15dd0e7dbd47383e33000000b029717760b130fe9ff79703c516a795971982bb796d7591a8f46fe8e4388e6edc523d333f86a56e3581a6ddb99baedf19a9c1da1c3258c4b9705d25bc4f768f3565f398643c63bb0ca4343c4801d535b9d0544e6445a334c7f63d2bffca4ee7b77bba031f605bc358dc17cbe9ea2576191178fa03bd2beb541b73b525c557cbcfb215e1f50dd4406458d3172ab6c953ff2606dea2714bccb19bcccbbbcbc386b3e4f4485ff3988ccaf791fd29b95bfa2800000168000000b0266c325ddba9954385fc0ac227e99a98ba966e2aa7868c3090da7434fd6ff2c33040bc2619aea948bc4bbb0ed95d31849588d0a6d32947259e18aed3ae07cabca452d1ba2a75727ac25c9fbebc1eb3c0eab9edae44cf69478a39e2626cda834d70c28284bcf1ab1d5c276768e950dd861bb96d91e305a802fb6f93256dfe14957c6278d454b5a9bfb784c96175e549ad0f4689193a9e0848af83029995a21434e01c0fc80ab40e55c45de06b562cf036000000b01db4a023205330d7ee7f3e7ace12e88821f87412e70a97dbba4cd9817664a0091cb8f8cbd13c9bc4ddbbff41aef5d5e92a4cb219f303d191ed652082b4fa23d6229b814b2451a7cb74a66b69d10f80169335fd29fc85d6c42d61839905075b4ab77613c5332e45bb856d71d8553e39f61fe603a7cbdebe6d4ceee14867016280ea8481283e69af36b4bf5ac203f9b08b18c4d5abb83b651e72ce322d0bcbe8a9031eae5c5b0868719f28d377cbf7033900000168000000b004435576a04b9a84f039427b21d05f34547b52699a4951a5a57d9ac8579cfc1b6c71c2d62f9af572e093844fcf470596e366e322148f17493d4ed4c79964730cd06d095e9930e16bfef0c928e302e2f93a69d3cff0503e77608e59aad20a6e4b0a392f7ab43bf9d08568c96f9f4ec37c01cfea0513983d639a933c7c9cc5802270c4ed861a650d658ac087c20d8b660f1c68e93d244ae3970f4ad31afb579fe46b45cc5e9cb2528d34c0db1feebce553000000b002bd373cd789cab3372f0bf91f98d78b133b125b70926f2019b8382b944ea749144ca64960bdda19888a87393b136f0d45d955f44d916296b1142d3f1724a0ac63d7be882d4e403c1dc792311e06e87b878193627c637816916c331601f03a608f06060dcbce7c0df3aa380e63b0ff05250d5b5402a3d051c70803e5735e1f166057a974308eb6b1149ca6ebdcb9f789134260a55c006aa6b6af4edf576fcb34d45eb463359cb2986b29cec9f083c8eb00000168000000b02870cb8e5f7bcdf27293a5b7f53f709d33af95baef20ae5d614d2d91a2fb15fc7a78eacdc2e434af5a60cf3bbe7c6480e40aacf8d29efba3853f5f2b2895cdacc73e91518b3e632c8313c91d18b614bd401daafbf587fef0d7fef4b01fef55e546996e2df28249ae79953c1fb439e5f30de5af0497ef73b5e63e2ac190ba41d47f13d05a9398f15498abb6dadf78e133190b6549a93ccde391d5f6afde3fb1122838fa1bb8df3b3caea05761f6144359000000b019e03c1f18b70c910020e39bcfdc9107506cb7b5f8d9aea17931afa715acdabb1cf9f97198a01e2a647a732223519c983085c761b6e131b5571eedb3874a954375a390dde79bc268a1619be76ae581aae0e5e2a953818c5dedfe8f17787c4c4a29cfab1765e311b75850473bea1fdf30152b6f4a8c189ef271bd0df141443c17cfc5bd199afe7c3df62fabd5c505667116780efd46226c38e11debe5bf41c6d82f7e9da1ce22f8cf5d3c8c635dfdb5e200000168000000b01741bf2e9b0ae57ee596ea73535d8258deda9c12d865f0972bc8412b084e1b1f7e2e1da1314d77aca987008306a2137863f27a3751de383413acc35f0aa5231afce8c0b0dcc3e822a3b164eabd42781623ae022a7a4b913db3c772dafef11df31a2a9311fe87cfa57e28645492970a3a0202aa2f00ada033b28f572191b78039eaa14f5c829159a807044181686a3ae10d9db5fe2ef81b100f85c1d1d87656600fbca19cc17dae490f1213d8ea2d095c000000b01b56c14ca3e4ec13086b51522cee66d91b965c33223dbb76106259443f6bcff5d90a4060e9e99914cb891c1b32142432bd14f8cec73e98e95b18c169238a6666cc76e9ad03e735d92ced8690ada973296cf01f877962c2e309a935f84380bbd9cdf63071d59789134e1a8b20997dfcf7006cfb283489708a946c4bb2da6311b094746762c42cd4109b0f48ed22e806550578d2774381abf17a316bf13a820e01cbf9e34a6e7aa20e9ed201bca638177300000168000000b008cb4179a3a2b5f3bfde879b4f9e02dc9530106c85c3b8770470874542663b73be2da45b34e4db090f26ec53e130bbb12d534b79bbf8694c4e0f6c826cc967580ff90207ee5af29a28250f0cb0d239aca3dd0a70a95a329f318fec630bc9e493d63c429f651cb1463244a3c11e45907a09d05f8de44a0139a4122adbcf98ccdb7d2dd4d84e9f20e2897285c3abcd86ac1413cc9f8e86491bf1d65b0a90da818860fdc615e6e2a09c264d5bc51c4f755e000000b01e3619aaf4f7e80a503e2ad15c2dbcd20b461d0d8645f64f5a1a7b6ac2de4db7f8384631087e5484e8721b2f782bb45d880c9d461f6d13cfc59826c93e64af19a58a40d891c3d06099ade57f2c18d7ecd6ab0ebab35447d3dff46f6481f319be27b7205ea4ddb0c55c98da8676004a570b9dcb0eddcbf87a0174a8afc8d3c4288887cdeb176768300e708c1fcdff233e17cff21bc2cf4d95b233ee9f53d8f5873b34608a07ac2df11daf77c1215dfe9e00000168000000b01ad758e49bfac25abff7a78e866f995167c4f18002f32bfa41cbb6f907bedd70c8913756670298b74dae4f18a062bf112fdeeddbe3ea74f787ab6745b8744ca9ed869c7ca37d1953ccd3ab2f9965480803819782857e0e94c0b6c6198ee14a16de035158882adfa36648f5832eb01229255d3562cd46b700fa14c0c30acb853c101cacbda258fa6d7e319e168763cb1513abe30f28faae397752ff5c41c65a5d7769edcfb7fd9840497bf5f4cf4aff77000000b025650276ebacee2a86bee0d4eaaf6c0991b4b9a00bb090ad21c8efbfb7abec111876d25cff91ca22587f89467dbc911599e0a27a35b9d8256ec4553a186bba3dcbbbf89af249bcc549163188abdba5395f2f1806b4fceb126f36ca92a555d8cbc4cbc462f2d51affd06cd1d756f0cb8c2308150bcadbabbfe2a5bab2ae6b0deebcae541dd6eb27f92a8503692d6e47d623784d8629cc2e09c2f52c15a34f7c3f09e0cfe18d8ee54072ea2c5b758ccf0300000168000000b00cb0bf437b59aa5f55a5c8a4e63e0ab0843160799f77eb97b9d8c321a6f6281730c7050dbe371ea55396bcebe87e0f338ac0d4418f4fbd685e2441b019e8886792b1507703867c4aec351d4da2db48de8fd3945971ddd7f1740fba0e2903de9fb484c45beaf10fba057c192dd15dfd6c2b68486101df8c79297782d477334b38865cfe05cd581d309128c6b72942a52e03d78eff9c56512be67681d896e64c701eff666d1fe8912827d7e570825a3965000000b01240e8c047edb175bc00837fe1a1bef2dd6c5388785c5bc64c0c618071929adfaa68d0da9b816ccaeb475d77a27fcbb96c380851c7b06afc1a3d997902ea725a6a735d5f083104b90baa4a160486cdd64267c41555244b3b825a7e679e896a0984476257a22f6de695c3bf8caa308afb10248aedd6521789c8eb967044d83d3e83846a2cc26d4780577e258868e2663e03cecf0f17f8d17127fbb74477c964aca5e3aee8a28d77c93b78ef85be6428d600000168000000b01cf6f40fba149a9d4f467489528c5d54e9de2f73f0b6698428463e018002757ce5026d700d2155766c2f3e383f15a2f939dd28b12593bf37d6f9c6d4fd2aa51e543b7c2547f51bdabf0586c918618fc1c063070e810162bff0e35d46ae890a506d149e05ad242b02fe0e8f56ce84716511378b10ba1ba8fd554a3b5f11f57fa10503cf68bf25753bb92abca625ba70a6303b5db78cd98c2e88e330de0e30dc9ce7361881cd99058e721809457a62a921000000b0062f2beb69d36a3f6ced2d3963cd93d152d8efc7bd058e73509ee16a620b58402bc1dd535a003fba61990f7f30402979828cd4e2294993c21da6dfb5d5e80209a24bc8f46e7f06fa0b5f9b446398b0a6d1bd76e37c3835cd4b935a6c526839f21850e9976552a2ed519ec21441a6f4832e4cbf0391bab306612c8a942360a562f48318e72dfb29525b22e8315fe4267202ba7354197ba3229064d001b029acacf62500abbf646a60cae73a10f1b77b9900000168000000b020a0bcd52c770bf43a022bf1d9f07c783cbceef93097077a73b840cede8caf6f8c60926a154914fec7458bb90ada66bf31400ad5494d317053b1481b6e79d4a820eba4bf384a9e8f6ef8986074b9e67ba5806e3f41da11bdb1dd52cf7b63cddfd8116d148ab5868fe3ccb8efda7e0b2626786b7438fdbaa33c07324a9c8ec0408972b860290b5b711fabb2a2fc140749206863858865c307161f22d1832b11b4e9e6351ea0262a0a6928225978d4ff64000000b006d17c7ebda60b3907e6f27c8fc30d57f21adf9fab41657458830d20033637eb3bfcceb8ad113587909fc5acc556b25ee90340efd300beb2a8122799cc550d61a05ffdf49c07558cc3c1f5cc163d475439fdaf8293f977155b369366ba1565d3da0e304f89f58986c68807d32621d4cc0e14a064d04fcf2a2e863163b4099051c87d628c11905a6ce144fdd5f0e1d1080bfb03498aae6b62dc762fa72b7984aaf3600567506aaa82cb93b41aad8275df00000168000000b00da6c2799ef24c52d2487f780d9367c4fdb2accf944dd5d2b8e376e8b4eb8f35d9a9158fc2a9c81a6810a47e7a890c6144bf4e335614a9cd5bd01298f62a963e86a20c819801ba53290420fdc99f831c5704d7fdde289bc3313e20e97082777f5ff3aa73aa5cc24f2fea02bd5ae78b330bec91ad4714c59f733c4afb567e748edcc0b57a9ddd636e35718eab36fbfb590538e13162a0051f5df443ca014e5ce6b1b846b481aeb295739d11a0fbe9001b000000b0300ce48175064486cc3f08fadcf972544b0c3d56c7b2bf57d5bc0144020704b16453609972a396e9981b2dbb159150a16d10274ec07cc3592c95553472f4edd57f0f48a4a7f1f34ac3d07fc95d577333dca85fa44eed03cf89c182cc772cea94cf3a63a176a84a48f4eceeacb316301a17761bcbca000dfddbc37e7769a78ee7f864beebbe8c8baf043f5756a4d498a214b0b483c05a144db5b668d03b037e4c79fa449b99521f247d81063da1b0390300380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b01aa06ab1254f91ee8471b5c561ec170999c4f08e981521b8dd911925694230e63d8bb9afe7632c3ed7947ef1e7e2ef0bfd6d64ca276bb5eb7e6c0421364f56ae44bcce2fa13e5de32ce1186bd0d8dfb304b5c4b2b28e36eecef99164eb615b9ea8895f86e838a9b0c05b8f001738c9bc2d7189ff50cce889543257cf1f4bd1c91746097c5ba281c731a44d02dd364fea209f85f5c02f1f0eb334b5bee90ecdd6aeb9789070966ace1262941f558d00fa000000b01fdb30f6189b90fe3979e40a22480b8f660ca485e590ac0698602b05c578400fb97fa29331b09f83491297aa57804dd774eac55ee03af2c9b9e298bd554b7ff87931a64d873eb77d3677778eaa1eb67cb57779b8ef3a950c513a82e4cd665cbc699537600b3c0dd224579cd9c5dd55590249c2d29305663e2772f8670d02de1002d1b8f0ef50bf27c4fc1cbced018ca31daa8235de4ee5d98f126cd6d039d33bbf15df20c2654baa3ce92547102b61da000000b012ecf3464f57de70240405289fd0e47ab8d5154d792f933416c4f9e04dd955c4bc3947c517ab9f29dc3821759b4e74ac0e3fde5db38f518bf6f0d545f16bf3552ee7f09ae666d3695d016243b950809d0e3aeac5c6ded23e1603eb8c984a29ab8a8b2744bce9bef2117a8d7b373610bf032f77782c26a693f42087d453e638d48dfd635a677efc95f5e6be287b3c220b0f3a1581075a59d3423a31d0489b3f88c8947f1f9bf00837b49234478f6cebba0000021c000000b00f882650ce9c1ecce58a9e2af823c250c2f69ef1e65447fde38dd188d370fc3bfa7c831ec754ac3c8cb02d5eeca6ca2a62ccbbe28cdfdbdd5d48f35f79f200713c170c9f6fe79af5e18d266196ab0b97265f12fd3e6fe92d0535315b62260ee6215470b8168258dd3220910aa00e81450d3426a6df5f0b656a20b8700ff841aa801f37539f75759599fe22ddf643c0f2021c3d43f655259e5e1a69754a86732219e9dc32d43d7b8e1184989d9655a40d000000b00f49243cf87ff11ed1a566ae71a1f837c94e42f9a14a175832b2f41c74184135108ced4d0db7b9e859dcaded446f5e0ecad710ec4a8d09f73d5d6b6d02de89e7bdd48005775a90a1cac3f55320b567e9c45ebfc31d57e9eae396af839979a27e43e07493b7723d8340c55b1d8dc5ad79098c35acc261345122cff5947e8eeca53741e98463449d67f4e8d3c49b4aece123294efd8f9adde89b5560a5a34ddf107a18b6b060df30d8a2ea19c2a8780d4d000000b00935044164d90a38b58c4578a5e4bc6d069f106f5a7516aa76ef6bc2f1574849121b4378d511f03a17a7d36d301463095ff57da3e04cb6125c4bb3925ae49607c431a4265656fd6e88fd6a36c846952a05e3737945603b02851943fe489bf28886d87d8ad883c49a969c42c49390687f2313f28a80807860da7ffd4eb65bf30190805f1b1a8bf9bb3c8c0e91375138ed2653b588d17b1fea281a1db8bdf897bab2cbc5da3745d5cbdf29a18d67cbd63c0000021c000000b00d9ce5ab737b6ea927aa6e69dc138f392940bd7409773343f249eda6382cc6cbc3a4a3a711d59e430d161591473b95ec92e6154acd686e66aae53e229d7908d67bef2cbffa29248786b72041ba33f0cc0426038b1ed0f18d60c3c0c27db5dfe3712b60eb18c93bb8dbd148daa2e8a01713b11b3ee79231260789765087f734a0e7de3083a7f617ce8b72abcaf1225ff91bd260b15f53962f3ee7cc5ee8b85f484ff6c759edafaa87e9de9a5463622b90000000b013727b9b40af20d07bc23155587ebe8e9a548bff8130232ee316a22b5537ae392287cc2422853a85facbe013a798264493c75d555336598e049d0e6afb783f08ff0d51d2eb2eb87f35b9ca44c5eb0de045e1c64a95cce0c06197fd7d6a2f3b65ddc64b22f7864d1b4e5d00cf6692edd511fce1585a7c86960a38d0fb0ed8cce1e9b48ebd99af0f41101762b262faa916189c18f4946d744ce9f1e3316ec27e590bf5099aa5cb1197b0bcd2d527ea5daf000000b006ee70703c756f68d9d7da4d18c60387037ca4812f9def0ceed5f9660957b70c166c32b9124104ed6bd5ffc1c7b6071a5da2e5bde41a05990a843275ab94b4a36371ea18158938729766f20efe1380f82c620177f4cac5dda257cea80d04a4231f5089645dc9232ce2a3c5d08ec1047715442ac2389d286536f2b84046f72f1b89c466c38fcf1ee80d77ea9ca44e4d5d2ca17d698a253495de636978244a9b11916a4a31bd4c5efcb78f45abaf372db70000021c000000b021773ddd2fdba67a95d795bed5b2f8632757e39f2df31c7b598d71722f62a28ce7998b844b055308864283ecc7e96a03226a1ce3693098f110cc969a500ac5f3e370149f74d86d3b649681b7728e5788b994c8909df98ec864ca3fa21038c5a69c6adc774db98d04db1d872bcac6dc2e210fde63f49e1a456f91a26b490ebeed0f82568ff2a91dd45010738235c747690b0718530422db090b1afb3a230985aa60906f52444ec961af558b6f636e326a000000b02bdf64b547e00bebece8e68d54c2f43b7984a0312e61652a67eccd638cf354897a8b84fb720a5c9ecff4ba74fd007dd5296e0a25bdcef46b1f6c0b32329e1532a346ca289f5dac3de0d8de24fbc6e7a3667fe8fdf964587683929cbfe08998882f772ffd0ab44a896b302274d579af3c145be963712f5878bb199289a427f9431e09590189bc7f166fb81e3e81099a250769cf6854c1718d012eba0fd7d3b95c7d9ffd177b279573a3300133eba49010000000b01ef772f69664607b67bc35e774523c3a51cc3b74e8faad3ef6948851907b03e86697ee1bef9bd66338f6827fcaa2c49464bbe65370faccd4d15ae9e558e1be8a8778c4e8bdf334e3025faa6e2e9a8be10b42e3619ba68de7e5dd221bfab15aa373fa2c374d63f9821fe0fd4a9adab78c16ad40f8b8a85e7890d651a158b382568d165cc6f016fc92614ed78e08e0807f28b4aa818eee9dcd3b24c073c5ed23d6fd36ebffe92b7a3e235562771265ddb00000021c000000b02bf6837c87e41c2773e6566264ed9792e4e5c8a55700fee81b60546af75bebbd819bc0aad1e269b84839bd240f18567187e5b775fb85ae0f50024994b6a920e52864bd3c7ccbb5dded0999f7d9538b5b49bb430d0d5ea2ba2bb03ee889cc8999f1863f04e707b0d26afbef5348e50844167f7ef611d6057ccb4399a419d11dc7321e03951e10ae764c54f86eb17408db2a3d4b93a55ddb1e91f6d57820ba5964c32c4db132e6183f71279257499288c2000000b029e553045134f4617eb4db95ed0d70b06e1cb30367c5bad207c62bfe50f4c101c8cf7f38d7f01a4aa88a64090d3aaf22d15f3a1c271ad506654b19c6e02951de7da486d36e69ce71de09e63dbe14b3ec0d6eb2fbf1276e06ddd1d18c29480990ae920db200d1b51cdf552ecd1564b286187f6e4727e87f7a24db6a1993edbbab26bf010fdb5e89cbf6c2ca5cb92f25c327cf59791df0fe93e9eac29b50da51dc60943b55a3f187498e86ee502aa697fc000000b02fdd80a505729817f194a87ac71b9093d5d09a912d96637d66646682d889b32e21f5e463203741a88d6cec0baa5fff0e0356f9ece1701e121c3d7c921da35fdb98ee6e6a4d1389b0767d4206f3aa4f0dbd7b8a36a02fcd075c458b99d165eeddeb2ca60885efd08c3e853b02ffc7e7c20d04d0dbdc127b19c867a29390b205fb0d425e345be693b057caa5ba59e468280fb3ba825192640f361a00279a3b7d8f60fa0f3009c5d63f11e79a84b296827d0000021c000000b01fcf3dc75df0cb8c99068e2e136f0854def01f8d975edcd7f3e8283a857cd6093a229da3b4909dcd41b43652323185007450efc5e35e08fd960c7745315dddf992435eb5c6aefcb9f163495d156b07f45f88702c7eed5a3403b735d600d8346f9acb3e9458669375cab4e3a58d281ca417a5e25e3d76574e000cc351c51d6d014a27f62bf857da694c43eb9313d4a3031918a02866245987c7b2b491a355dce00bd155b25b3c2993ebaaaebe42b2e7be000000b00db5fd906333a067b4635d96d34e1e4cf38a1537754c1a297034b3a29b304288b9d96217a19226c4a4bcc3f4921106d26c6bc388cb6998298bc50c06739417a6b9d8a60cd03b3ae2323a8aee8ee84411a86c34a0888db257ae9fa526badd5c1310d36e77600c341a0245881d7f3c860d3049a233fea282bd4ad76ca51dd9b6645dc2f455c889f2e190b896fbc012bb5023df873af129c26655c4fb59112b1ab9d5b61b143400800cf7301a7f460b852e000000b023d59f676d089630a0e4a2f3aa805bfc62bcc088df5e074c0caf440241d5d4bbcf494db02414f237e4d76832f6e531673bfe18321147f10b136c4c13fb5a4a3f1511f0562d733a8180892da69f7f8aab96585eec29d533b5e6c45372ef6fb89fa8f8709c28a75f85761c4451725d2f3b1fad864a0e6ae76680e6f5bf99d1d5c5ceb26c93e1c8c97ca2921a959fd3d9d717ad9da330bc18b3bc01f528a96c889b8d9508509448d91db9a934b0fd3222e20000021c000000b00d61ed602d24f4624429ad57f097409f7b8c306f925811c44e46c638453768bbf4164911174640fd489b284d8a23692923a5bf43e3c6b89f9fcf3a809d8bdd0a1b1fd4695cbbce950857e9afc0e83bb30611f39c6a9be5384f9cc1038a83a29408dfb0983250f4ebd81037648f41551a243dfe3a30291527f4bf10246d8697bb22aab4be83b0e6a2bdac43273e95c44017ce5e0f84c3eaa8bacce0170c4dd96274a5f861634578f8543be54e264d8527000000b0096c98fdee1b420d689fdcfcfaecfcce8dffb1a5f3ef6a37c5d77a8ced40e57fb4de70d931635bd49d561655945ed0524aad2f0522b5f7e3f0bf2cf1c23b6cf19cef8478cb1ae52a1fea161f4b11e6325a741c7bf3c5ac78010977b4e16fce5be0553fddba810917009616e797abd7e8248f6badbad7c7b4979f15466c993b849cd267be8c0ce8cd2972478f6b2246102f2e7b3947aed584bcdba18138e51f3aad8e5e5bf290365799d9890a948c2970000000b00c056280f4ca392e9389a28cde902b155356d4966aebb4cb340bfeb1e76249179fe4f54fff6282d1ed01d929baec734eb2d4f81cf2424fff149e3ac877fc5e1efa87e206654ebba38d2bd036afa4b60d68a4e7261d4bea83ba938f3f22053df17a4855876856cf44cb49091401ab27ed12d4c5cdae7dccb33e5b824bcaa0bc50ff2f0b3b09949e6890ad52f8f5617ebc1146edff5e0e2243cac348b7383e6dc2b5da6b948d77e1574bed396ce64fd7170000021c000000b008d7078b7b7af8b1865cfac9c784d9d2e24ccd141a7d96c90079a90d97aca8cb133f956f33c7c629104f6d9141f32bb1481e37dbfcb409c255038f164ab19a42173fe6fcc69505274c83e5e8cf26b85520e51fd0a99ed37af826066cbc4a810ce081b7c9242bfa5b80f3d7976d32e5740e00e64556c424e839818af5afce0801315e3360da2439a59001b246a5dc40b524dbe3238028f7d3d15428b63a646e5bc1e6e33e4dbccb792cc9619b1eb145db000000b0036f2174a17aecf9ff7dd601397ed3e07e78940417a64ef8605a48f44e80caafe85964f032b791e9d0d8c67a262f692a59e6158ab0e94eb627474a90199a6ea75c8394301d53c17f014f67c5967a50dfcbf2f499b100865e0d896d1b56e435e8f1203bf42e3598c83e8b6398c7199fd116d00f909c3ad0cf7ddc635ee9bd1d394ec005cbd44dd163d6c1180b7bfe70612d9ca62c02ac26744862e5829fc21c60218345e7dc92e2191759b304bc02b2e5000000b0279dfc0cb90755619bd91f0c8812deba8fe6896442175e80503fa3d340c39a25bc5479bec7ccbbc5d3a95826e56283a434b3c206a79b18a7a5dd2e474a25e1f3cd1668e8bf2813fbe02dbbade79d7ecc52de9554dbf8353166aa6667fdebf3f7059831602908594af1c25ba0841a45641e3c6036770d63262491421f43521a514a74641aeb708d27b44c42fa401c2cff0a9d0c8a4ad8942e5627affbb0b7595bf5a187225c441671c4db250ad9269cd500000fa400000168000000b0292520bf4781d53f2c448f7eb6dd4b1b5bf5016eb8fe1b026e31c82c5b1a30e26c0c25a528d6adbb8631fcce7ec7332af174cb0c2f4c523baf8f3dff6e13a19c9058dfb65e5bdd5e4546b6c4d71d82e31c0db99535dd3121f0a484c7d162ee63e1e2c001e68f6e6914d94c050c1cd8ec1d69b1dd8b5014940b173a3656dc005455f15d226d433887f22460e70accd29c2af8014e08f2a1cf38fb31122f85aaaf72fb4fe93d61d7c7e1fac0132f952766000000b0172b9ed3286a8b21a8d08c348c94cff03c975a65e25a771531ebc5743204db7e549e81c55dff16ed3e9bba9f102a61b69b3bcb992d3ce89e25e53d3527458644d886cf857ad4e746a5e677ecdbf94b54f72e74200095cd907f37647ceb1fac1c3af50d34b5be1db60130c5888e58129c108b1c84fb08ccb89f01d8d137d70887cfbce862bc196ba79e4c6b09b455f7e20db609438818e0438f9b48d23cfc55eeeff691b4d79bef01ac550a8dabc8690700000168000000b00d9452ddba1268a4412d573eb3a0e4d68eb2f8a46518d7113968f00eacdc9d90714c0a454486bc5ba166d478e68cf4d487a625628acc822f5b3c2a5b32975bd41faa31c909d4aecf2e13ad09321cfa3cb999b0e15b5bf31c7867e5cf95b94e332dea2c617e534745fbab0d2baa43cdaf1cbd68d166b31f0c7c0b45f8542e2e06ca0b859446285c43661c2d3b661a443b09f62e3d055f0b4183035db1f2da5a094336b8657c21d219651fe25bad9fb811000000b00862fecb3f80edcbc5fe5824dd02987fd44cda5332022c27807fa257b5798adabff31812ef178822fe503fa2456b687881b5ac5455785d7d7b2b3c64cfb380b45dda803d980abf643097cd0b7400bc2a56c646383d2bd7b0c0b6ccd8aa99ffb7084b14f35572fae28394e2dd09b385050fd3522d1e0e3606dc2a1d69852c162d7c7ac6410be6b8f73ccd726a783e1b9801f4b1bef06dfee19e1b40f496f730e41c92b6e881acd14ac5ecc2175dfa85a500000168000000b022e1876563766e62225a97c4ea1b0d933befa948e9bff40a36e8b1b77e654f5cdae6d6f55c3d27adcf7186c4d5fb0dae7a2ee58da5ce6792827944f8a8d728cd198bcfa1257f7d1ad87d7d26a7833df36426df746fe4866fb3dd95f8611b1f8cfa7dc3db23893982bcfd131492308e550c45b0856e04a4a9f77f9d0d940b1f7c03b1d1ac95edf0be8fbadbf69402faa90090c400293b0dc0af9fffa60ea96db3c4fcb7d9a1e8741020b20d7d4687c184000000b02af01fc529d148de4607a78730919ff88d63d8c900dbd4ece11195afe187a4671b27eeb63b75b252ec709b56da7ce018a0c2ebea65bc2d48644a08be4bd01bd456ea35cae30936874361fac1b578503afa63ac2468781bcc043d619f3fdab86027c709db92ac836906d9ab06f58cb07b13ef67dad12eb0c6436bfda295ac87542b9ba813943706101a9c501c853ae56404bab6c2a88a08055f1c376ca38174ff94e6919b4d69e7adbb61a65bc4f8d34500000168000000b008f0e07c2734cfe7b42b56247e89f2ad44272e214e2d7d6cd933363559094dfcc4ce14a43e0e4436d56b36b378d21a00994e0e79f12f896d68cac6a2ea50a8308c2cf0bf1b9ca56bae5db8fd28c81e128bab92c1cba56e3161e9774626189f878516d86c07cfc26d3a17d7d05d40933903f99b0bff3a43fa7bdc0e0bf85bc86032679649e6475ab2dfd43f1d8db95e25298a923e34e15833b7e245d93be31c9c748833499f61971cd256da2c2cbcb15e000000b021f15458b5d0a3bb2126fac1387ef85a0b2dd8abf8cfe2a0971ac942f9c81782fc6b6a083dbe6ab751e760c4ff3b1c1794156eafed4d0d00f7098f9dd77b70f68ad90bc02fd3f34085d323467a5dac7c9a524809d7546072b365de9aa1f2f1b95cd7b872c95528759571c9c6a06299801f79054eff3871ac425b847485c2ff9d460f8e1cf4bac0172dc715610eba486f23994f89428566994602bdadd8d9fc947eef88998609e5529b649ed286e4db3600000168000000b01e8d9a1d8d538f09ba7a3973a1e3bd4a5529c6f5c3fc04302967249c0bd9127ac04acd76f1f48bbae88f10355d7cbd0d7bb8d6d0a9c768af10b36a735f8eba09f25457aa57d986fdbe7eac57281f387006d46cc3c407560036a7bad875b03705dac9dbfdabd92896547f8b42d8423e0520cf7b35cd78bdb7d644dac8159ae55de90016fabf242aa0bf7dc557e1df73641fb3f38429ac58f56c85e46d30c1b03930d1c1400994b3d3eaf6b7bb857579c5000000b002e2b2f34811be3c502b5918b93d1477fe8e4082d8d0fb969117b2f643f222fa86b4bf0d8e739a1e8bde614f1c7692e808703dfc7f10a0f2a0d303d4bfdebf6073f8c98187ac687e5025ca032a023c7edc49bdc77b298bb3026d26aefbe6fcb91f0c8fdcc71418d60be7333758c0a37713e4b2b85ff371208d40f38cfa3d7fd958123b219b71e94ad907c0f0fcab0b52278968de7ace2f37560b3a87dd9aeaa30550f147fdbe781dc3395298291c1e2300000168000000b0194b256f950dea5f893ea6616cf93aa78405deb5cb90bd82548a36dd439c72310496ccbb01cd42bdf6c582f242243315023c02d3ef70d6317b7c59176367d975b94718485d1508e751b9acb3ba995db8ee6ec0d957020b3c067b9635d3112650761bc1fc0eab24df6b7c7f6b510a176b2b0f84805f26e77422b0f0f1c3e3053cd8f1e72692a2273ee7a4773ebd79ade4192e9fd636b01729f4980e1ace62e68fa8037d3d29682715440a38152b120151000000b01e1a40e7795a4aff01ae42bd90f3ba6f3b79b5dc6710330d6ad495861bc649ec38554bf282b9533ec5d55fd1549c5e1d06dc98559a8535dbe8852310369780cb86fe504552ee40abb92dff1ffd796ec752de29bcea4133386f94162395d839208b1da16821ae7221e148ff407f0af0320e173a6b9dd018825379e592582f684d65eef7ba7246f63fa113e7618eb0e47427544d6fe4aecf52a23e583db9e5c84dc3fe64080216049b8681154f0cf0da0f00000168000000b01997931193ab71769124a130edd32a0ff5181055dc47c92b6116c3bc28d0c3b5f9c591431c2ebed4b9ec76d2b130612d7cfd5c457b10a028ef217c374c409d9a98d19879f20b1787c01869d3c10e9dd0c7332d96514d21ef9b439acc0aaf3fcf523f8b44a1477257f6839a27a07c20db25b0eb6066f565cff5c342f22f8ac0d8fafccdad811679abff740dd7958f5f0707b1c25eeb285618b9ec3f3f075229e62fdee70b6aab8c7a6bec350501c4cd27000000b02df0ceea8fd8882e51e9e8d6cd25d4bd8408589b2171e7f3a1707b79482a17b9715e0aa693b7bf73ef078ad21533459bd829868c7b49793218a4bd60a7be6eebb82a7e296ac60e294f846b4004ce968eae446f0eb4c935e284f0dc2e9734b8d91d088cb4b83a1fe79fe319a63653523715f78e916e2f9b1d6027a1b9861af1f374ccc956fd1379298ea5d5cf268c21980e17f251ba18723fd8a52df978f6b6a59ecdf332e658698cb974a71b8f5136d800000168000000b011e85cdda28a6889dca63319aa3b5ef5053a5925a53e763452bc4e5146c134be37ec443f9c8de8252a28577797bbe7e5890addeb6cbffde416c608e5a5cc6b8562ce654ea4d99ba028ff4e9c0833928eccff5e45ec2007e333266d8a49decb34e03efa8d6668d26ade25050791ea5ab11619e0f644863256f8c0199d8dcde76686ca3eb756a2d2eddbde6688efc257690d3d6d3a8ce70e56a4a6a69861181ab710141a6189176c65cbd42da56de04073000000b02e83766229803608d8ed0d22827e5a975259d9616b8daa3cd5eb33ec3dd82ff4465e78cb0e68efbe9d87becc54d3c6b08610e3b583875e2fb9acaf99ed37f664194a161d5efbb0ff48f6d27157323c2f744215eff1f96299c60a2c0ff533b39ca4a26ad6d673bf3a6a4fd06f54cc1a9928d19bf768ccfd02bc0617a4187f8fe23f5d01403378dd0240a8239288d132df2f0699e7361745ba3f1bde6419c87937f63d1ec7c0a20ad46dc5c27ef165093a00000168000000b0047b3d0a755fc36dee8980c418179d44b55cacd034673f580d6cd2d20e8e040de4d989f654ee48a171a2a09d7f8f29877c6cc0bde075672f7d3e2674b7dcd755a90b6cea3fc64d25aa221c905818ea797805f3cdd01c4118ecb5bc1434d59a53452d065752dc1feda781664911f37a8220c5b550379c7a399847e16f4e7b1c297e82928750e082342e42bbb32ab173ad2637bd661ce99362ac3862501928dc346fb3bf96497a4039286aee19fa4898e9000000b0126b97f8e34f885bea83db59c78b9698bcdaa406f20fceca80509f301b05a26bc6b00d4035b4db0dc38d54b9e94c79482b8cefd85baa50fe21e7f45a56ec487a986d19b1bc6796bddfd99af6d6be9fb60d1b3a642e650eaa66b27e0893a42341e0ddcdc296cfcb0230da18090263a0941319831680c06d6a02d786e1bf025a9bbd1208881022c324c8dc3d6854e0ed48104e7e94e90e72c75f5fba98496090b4275632a00832c62fe8b2fedb7be4f78b00000168000000b003c8da2537577d7b1244d7191b74afdb8bcbb49d09a67298527b7273da1d2bc273c2a6183906fb8cc522c8278d4370d3b9a22d03eca49a40bf9f3845e5f93bb73065c73b9b82621e2f5a7546bc10c35d6a68ac4dcff07889ca21357313f2884de4dfdb5d35c5b4fb9f401f33fb11e68d298f6f284bdfe17aa1ad7aff3420a0671073b9803c8c4a48c1c95b74060390eb2f3b7b26d90b0546168f57a10065b596c93ff4ac4571623712509ef84643d5e7000000b02f10cd1f3968676f5977440828421de349a47f9de357d6ff312feab6a2aeba14513f92d80d430baf88565a860eb5c8d441e7a45f8271aac574b68bab994db9585478c8dd06a8ea0b0d17cdb028dd816f4eaeadd07bccab3140e31e1e749dbeb290cc10adc1a5d45b5da954139344ac97084b4f87afb3a5687612d5b79a76560f8a7b6cad29915a166da264b2b7aa310d1de7b0d4f592a1eb4c97e86a98824b31313d7c12ca61153786fd4728e660ddc500000168000000b02c27679c4e9ef6b17595d9d19a9b980a39f7543ae1d7b7dfe7f25e751ddb670b878bfa691482917d1dd6822859e162bb42d652bb9a7a0ecec91f8fb3a6010b794e3f4c5d1c95d5797ab415969fc7fb7a0b0535195ea01ae7dcbed01fdfd11b4099fdac3aa819fdfb3dd6f76c29b859980a3059a299540a94eda85b46ab5958e76e6db7f77ec33b9ccb253738bb64262e07163b400834a0ca0ecfd2e7e1d3394041c6fa270e1dccc2378e920bf756c0d9000000b0001e55cdeceb86ce6fc811892a6d6892bfb0ba49a120725b5c32936517641586347a94f9aef1de6c1ae604627b8d8135bee22868b7ae1a41f8a0709184aa11ba0093ba204ad266b2ff563ec5a55367266cbfe029fc2a47fe064ba58d1c3311bf50fe04939d3962b75fd83ac3cf9826ab1b1dcb1bfd6444eb4172455fa6770593cd21860bede8cc920066cf48fcda1e7d075820dda613e744a88d043d2ee74efd767621c780781d89df1696f1deb24125003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b00c89407a778b90b87e5648889fa571d1051f5040a5aafbb4f306707424be6b20e51cd246cfbdd1d1b03c039236b50d74e55df7447497faaa38f7fca4b8f0daea9f91f99b48c5f4b7d89a3af0d04c22e6d72b0dcf6039d63735b8fa17fbf2c361c90651b5f09f521c9a56217970576ad112681ad0a92291e32b3a3c0687344b9b90265888f73399763303f6a616f74a75010c7cfd3b202dfd0f55ef707961c777efe70ef61eabe6459307c13e204e8d92000000b01defcce7a31cc3040d44467269f0550a30ef9fedb918fcf91d2894ca0f876fcc1c83f99890790ffdf6d733deb59870313f12565219560a75caad16e001f9efff60f27507961ed56bd05184a0a672913b41303f6107853b33b33440d3ede83e7bf96944fe6f39f7e93d8d84773294c6a81825e68f0fd5b95a1dac01d094f86bc3ad403b256c8ef94a08bfb1f59535b4270ccf8469d08b17ef3ef917ef79a8ac5f799b646a1788e81e865e890bd5b0d7ce000000b01649c0fb542e3137a8c5ea4a408298a450f6ec4c1445f64179d6bfb3f4bb7ee37b6cd71ffca7370ec11c8ed9a84694277735ce1d3a89fed494bded44d2040fd6374352dfed3aa07e797accdd603370791e78323f660d6eedea8c4d1bb650c850d6f3502172f494a364e0b2e7972412f603169c8975b18cec76b68680bab2594328c6c03e6263ef39de07090b58b6fc8e2899c4181e973b87a142af3d3ae11997fb679ce415f222ae5855772c855b03b10000021c000000b030192e5b75bc105d11e5f4b818336686fe2b8ccad6b1f1bc39d2f49cef7f7070072240b6b82a8e91085bc94c207318210ae4ea1f673d31e5b8053f8b56660a9c752389251518ed62a9db2a8fba0aa0ccc2a08b85311f815a9c400c1ef3ba9a933e0d3296d99de0fd1617efec959d46f30000a7204c50a1b1b0635ce15c7e5b00d8e1cc8546e9d5400957eb4ca7f20a762696d80fc51eb4d73b3f4735b20d87aeaea81cb4f9ebc5079b7048b3f9aaaa2d000000b0242c5e3ff44a56a352941c284e1ed7c0ad991fe91b9f84e25f3e2137b19e28460fea7e907063766e829f0d36186830b7cb4ca0cf82e401859d83ee91b61211239552bfc74cb5da7a43e43b0335469104feabb178f5d19b48f8c560c87b0810919222e5da071e5ca9776352ee036b42cf26a9a7fcb5405cddedbafbbbb282a738faa4b6fb0117dca17e4c7d40add0c4ea27a4bb803d7b7e273345165eebd9c2ea5539e03b37c03573e26b8ee6290fa490000000b0116e41c079a55d8d3a9b451ad4d0bd108a4236339837e7501da0780aefec6c942e9410eb9f0a915417f7053d27fec963fea30b09a88064b3e36b13c7e8ea9ef1286ebb3586a05e61fe5ab60c5d517a74d2c559d80a050f204a54cadd2c7a9d02aa2c42473c26c9c5dc5a2b852111c9630087a01148b559d0524dd4030de70b1d2aa73f09594eb7d60e2b487dac1720f72aaf4f96c8a3e7d0a68ce0011601854eb3bbee8802b36e88cf1827e3bd99ed160000021c000000b01ea79d537f687013150cfbae0d71f08bb725269fb2b5c8132afbe2aa775696b3fa90cb402c1975962f409b0c67007fbd173f0ff140ebe2889eee84edcc6a518124dbbd5a40fcb49e10327039c20a1e9a903e5cbce16af3f4d130ce326df8be55013bd4e7a889fa83421b6ac9ecba5b492fe26ef41bd61023417bcebc269e2d563ea87224d0e4b04cf6a55f8714e5f9e7062123510bfe773bb17e69e47531201b2e0ee3f18052ee9081d9ce170f7c2cfe000000b015870ab35631211fb0f4b2d3c96c341b3fabf594dc7c4ab4171ec52e07fe1d98a8af9f54d8f50d9cd921806a0f96d04d7c972100ae97c351872fda75d436d35bac84dc3a76d32ddc9d37b176547f080528673fa04e74b56076e8e45fbb5b548aa05fe4635d03433b92023bd38744e62d2e0135476878559ac73a0f62652418749538d6d60ef952ad527ccc6e497e0d7d2083113fad979f8311bf5a98f80a55d64f16282d2376eb546b77e0a215bb623e000000b001a408ab0b8dadaa40d9c094e8109002ea04fd9d13499141baa53c38f7930ede74d972b4290410e6779e6444f18dfb6e107bd7db812c40acd22892c6690395a4050b933aa73bf5dac4f9eeaed69d82472c8ce6349e2f36c2699874c6efdedfefb6a484f3e846d60d01b2a6da41a788e61cd2cb5b7ed72fc362234fc3a81f2fb586fb38578aac583546746e063af13be621982766fc6748dde89bdd53c28cf646ca0c47b4363ecbf6c94c1dbb0b318afc0000021c000000b00f1c4d691f4c42f2192d0a38895bc49e2e78c63c4d00c5de34c2c1c21bfe90f766ef92b4ca2a149b6cf408daec2a5795d10f34280530c33dad774d2b7cec16e520694f09acf9264a44ccc78d1f8bca0f1580bf0c11e415ca9380377982d07182f0aebf5487d093df0fa49eafc923d1ad2270fb59e55eb312aca42a9fb9314e160b27e571e413726904ada346f01a4c702b6ce48c77117cd0a409c0d4e2e4ce87d83ba936548bf02ac6c60df8e64fb10d000000b0262e283709c3045c9f97e42b262f346a613de326b97ed7ac4243c1db66c3b3308dca164cd92ed5be73b615864755a3df1e645967ed438ef86099b972ae83727d03b68b3663564c38da6f6cc11ee3810b4df67d16491668ed90d875cb465d66e4b18b900750bff3f56a02646d8730d1882ea423faa71146270c348b6345cc96b05d2c825543a647995edf7d7651c1252918bc195a5fcd0cc33751963a98eea5f52c87fcecc1e51b29328eead44ed04efc000000b013189dcca944e8e1948cf08e707bcabf92eb5a9763f240c3b92f6ca6a095a5c845b795c2b6ee06b90fd20002f92f8631fc98c42439f35c27c64510a5e7e66a35b4ed57d68d33a9aca56fa4be0764b726e3b4a3f411b348a28250f2aac0e1bfc772bc80f2b94a4bcc578f1bd81ac3f2eb0ecb04fd2e52c77426815edcb6e8878d76ac0b6c97bd59d5d516859327ca9280029008f24202a2e2598877bea482b627a2488ba0a4320a08274a7610e82d179f0000021c000000b01da9dc0728baf4492c12be23409f5a195d041a3f3aa735649b7522a3afacb7d84aae422d0ed482a81216097778cb0d31a171020d309ac53b2dc1a339b309a57a80687cf06817c447cbc641b07cb315a792754439b6d5d66b777a745a7d2b75a6cfd9fb3e8f386c56b1c4f979f69227b617ea038c369510bb3d4015ae7d4cf5cb2b55e6c75784333da9e1bfb338dbf6d60fee3fb2d4b9bba6002a31ada490589b698d6e56e44ecdc6ff6913957b8512d6000000b0293958e03bda0dd9a05ad012aeffc3efb7520c8ee7ffe6737e6ed313015f4f84209c9f3ded38b88fc7a30f0cb732ef0656af6b305733fd305604eec6aa37ac257958592d6a8182677dc20d97db0fcbe03edb6947684fdbc7274f397f612fdfa86e3bdb7a380cc8ba4fe720461684a248009ee11343782a953054773a9fec263b84453231ae0ac30e7049045845f59fb5221b99dc8f42a8d1fb0c2393b97ab3d86896afdd22da2c3b46007254b0f21867000000b02a98af33bb9e3c6c8a62d9ec544685ac08a7268eec47f11cccf64dbda2f9652a5c7753dd3e8dc1ffde8903e95edf69b969adcbbd1a87876bc6a8988c173cb6f332af2b05d60a1a65526973df6b60258a2477cc73cd3b30481922a8166fb2d39e284a3529cbc607aa384d90395ad8d43f1b2dbff9bd6a1308770d26644eebfc8d895e309d4360ab63d8452d4459608872075851f715518e21c0593f4294d9eb5ad5f2761a9951e620d3d3f565e80e000e0000021c000000b011e175da6293aa9bb297d435c794ac4c1815bd83f6e61c6bb0856c162f5f28bbc3274cb745967bb3cc3ddaec596955445009e403fb28c372b108da9d855238f147e41d8990dab40dfea595c95cc84c84ac598a8bc3608bf246aff5968f1219e384bed767fce07272817ce91257d2f3f20da780cf6b5f2a7c5a629f920543a996c7e493498ff561def2091631b0c4225802dfd96709a51c36759f7df7834462e4de8bb58558982ad8f88e1641c7ec0b19000000b00c1c740987397ae3b58699ddc77c6dfafc1dcf72564320cc23f58f9881d85f6b874a9519cbe52f2aedaed07f7b6d55b2f69c18f8de93c05d764417d672887d0ad215c937a4dfce1da027d8d3c61708caed8188bad2ce692a6c753cc4b0f36fb63722f9f6e336fe799d9526ab858951cd0cdd5ce4218fae86ffd5f4078ebd1b0e967769a37849d38feeec8e849a56968f22a3e1ce09476d39149a1a8deada21d46fbd056c010c2b3a26624c276246f1ee000000b00588329b044897117fc0067144253b2736b7a0da6fab20b6d603d01f9b8a3dfadfe66def044ef94dcb2b6efc0008a6b1f452f40544d9373ca445dc6b662547c5e9cf0edd4923474f8bfcd7126c0f36a1ae547e337afc0b2695496b3233e41afce3652a7410f1d06f695790fab0a28f592f422fb5766197fb4c2c50a585f19e30cc2c8b7482b15e47196f3593a34ec3bb0eab70f03135f5fb5550d7ed6cc07185a3371b90eca916217a87c3df6a16b0e80000021c000000b012fd87c3af79c69aee6c984a3c7581897e409d0d5191afeb25a06dbc95ed3857c0d69fc48146df26978817b974c9ff4592876b5732b75484b616b659326b10a30684b51176f3569e307be9e9b3a8778a0854b567919d40483a210c8117d7d90113b70ff40cf6828c7630d9081c93224a17d62c62755000687339a0021ad795224ddd97e07632ab09be6d1eec88d5a9211ff2f9f2737019a3f29e2c7d63707d70394d508ae146441596e2a9789d363652000000b008e0090031f731c347a570f5a0821134b821a108141ad7465781788f16c92bb5776c2b36011a6ec32b2585d9f50a3787c12485bc34ef090b07f0fc3a5144fb3ab0a19636847a9b80866d8b251bb1b6ed4a6d66498c2f43a87e6a5915c4338bc537d5e6b3007acf5924aa0745a4ae61ef1e6aca7cda03b9c14b82d0e8129563b78522bce26f2e2a1d57ae42ca5a6c77c0060fd26586b65a246d8259eb743cb940f8ae6a0d03f70d2652bdfa9ab27151ea000000b016db4a9f6f4ee45fe424897029ae5a7084edfc3db3a03868cb7cf4dab9e4b80688127e9d7976d100648d596fd3e507d428fc1d458e8a4bec83a6b31e113ddbac145e352f13b9f87d3f2ad32fb690b8455e5a26d54526872ef4fee7d11a6e21b16d0314e1fff60d0364a51d04038b0e251f9a1ea8daf5224cea723fd426d945034cdeb4acee33c72ccadd4a58c4ea8087075b2c22daca54d20c2817c9b07721de733c26671da0ed0edfbe91f35f9186390000021c000000b024530d4ae23aee8f13a622629e72e9607258909c2e69d7e76a7aec04ec5ef6f49da1cbb3bda63ed7b343309be55a1152c48078b90d50a728e15ee35a690765b79d17d15c7a74599f5126eb213195787500f480abcceafbd89960b797a6793d1ae07fc2dacce2925f915af309171f6bb52144a90571bbc7089ab8cf44ed2f7f8a6639cd4f5d9f5f005bbfcab704100cc1142530130b6e736f1a8e79c32e66d40875563e2f04a5d9b12dafe052b6b9d7ca000000b01ff647ab5b3553128251df693d05c6fcd94dfc1e91951232e768e8e00b41496761710b635e9e5a8d4a252a79da52b3ffc8cdfddb1e348482e7300da8a78d8493f7475dc552962340e1a14b418cb17c8d09e242fcbf136796ee63740a43ba83e291757da7f2df381f01217a8f04bbe507135415f931017bf980b718b9f8a1f60a75e6343f0e72e4e868a2c50ffda1d7d22d02ab41933aca301cc84cca8778a6c42ee859b63ff5b6132910362b97a5c802000000b01e66163a2755e66f81bb8704bc5c0a8fabb69cb51bbfd37917a51b0d84fc9f7c8a4365cdaa13f59767d3288c2fdd1d0d91d8551c79e985ffdbf4086e2e0c58aab6cbd5202d38da073d9545b3b15ec474a38eaf0545dc76a899857c3d531cd621336889abc51e8acf7db5039f84ba060911052e50aa8046c281ac26e9f15cc73f773dce0b965b5547fc182cd8cadec5fd0d2b79bc1b197497f6ce33809077c2e1341dbd99f8375ae17ffe13ef5fdbcf9600000fa400000168000000b01b9df8582a022288f5f5612576d049c0b1f6ae21b0b971029f2da85b9f82b73f3e7ed4a6fc2f13a7ed05cdc72e000cc28cb2986eeb7a6cf3cfbb221a1f337da7f6c672d58d7d8450861577bc993d96318c968d4a86b5e31eab13734790586e1b310627a33e2eb31a12b3bb192483c2951cbb9bce4f32b25b6cc3f10f6cab29dfe30ce1b50e6d77a02df200a63a0c5220024a7423683f9cbc9b3bb6cb8c8c3fdaccac7f6e7cb9fd371a2c1b9f9587b0f3000000b00cf85538d742b983a6205663e75d9c6572c0e533d6b4f855c24a8b1911e06614fb96ce0bffdb124b20231f450a3fc31f33c74645be402ad925e78942147498ab85fe5387d95390ab74325cecd76d50c65234325f5e377c277bdad3a02f39d92ed504e7c41992cf0f44e756e8a526f40a303d29a4b6113cd1b1bcb69541101ab9ef943e6935e0cfc5d60b31c4a34580592eeab3935b70bdb78179b78d4661429e201e9185f92052799472467213f4477100000168000000b00362f8be4348da15557ff22698c9ae1dfbbaa933d8f0118201912d5bef08b2467d5f60cfee5ac67d26ce39b4a919d959f9c9fd468048b4dc02178c223ce40f2bb9f7620d1ab613bd82e263f3324c7a43578faf16cfd04c6c25949db1f07cdc146a588ff69ef175f64fda88efe30ba52815d3eb3cb8ceff54d6780160e7ea54efc75b726d798f2c6a626c14354f6af97e1e045435f7915db1df9d4c395ebc43fa045e1d4b0534d6b10c0e96278eaac19b000000b00594fa962448a3bc7dceea43e6fecb8c87a8fdf91d4f83aac2cc2ef2104addef45c1bf192ae9529ccc04d08221aa31332cd8087fc802f628349ab8061c5abec65301345ab18ce7b1799dde9732adfc0945fef5abecb8b0e8ce15998455eb94ee04c5f0a04bc4bf73f7b3689b29745b7a0c8f33a0d0b3ecfceb53b5ea9719608b4f9fe73e22d4836f198c86a8740cf82e117bfd326b1ede0cf26e2bfa36fc2df55fdac8040b736789df72eb54221186dd00000168000000b01d0996ae53cdbc021043f5332bbf80331f8053cdf0244ae3d6dd4bc4f6de2c78055a68cd6d4ac5986b1bb60a59ac6f7c1db8bc73c556ac68dec286c8a35ec73821dfc7702b339db66fc1391a9e9f675503f630d6bd668f4b853621a816829176a5f00aef79d2d3b5b07b45daf1d9a86324243d505371d5b814e7aed23f68555986fdf0e8bb6ce9e79a43eb1e1647f3e413d67e1c2274dca01d0b0a4c7cddf09d75ab0d47d0a3325681d1f03df424ba1e000000b02935d908f567b7759359f66409dbadbed0d1089effe3d95a56ab63b1c22b4e672e94a10910417db927bae9bdcad3470b8a8b6e32ac24c110adba8cce9a3f4277426d2f816cdcf81e120b3d56d29597450c10054e3f2af395587a250cf00f7f9f46c82302cd628b4ce7bfc7b8232452091fd2d0be2dc0facd6ab34c57f8af729e79603f16003fb155cea9cc1ac9425d6e2dc9363f9d6e15321e29d76881d7640f17772c1ce1e8f152480ce6629b89badc00000168000000b01bbf946c7690763bf67ab8dabb68db6e7488fa4f53908350157feca354336ff9c7fc30c85e5203353c1eaecf104dc42cd01f7b321dada955ec13bcaccceae6cc97d886919ee1f44b6ad1fb5ce50023e0cacf253e868dce7b47326d7556ce99f453e9d249a08d115bf52b73b273115b572b67fb5b03d5f05337b87356000c69498a9aaef1551fae6e3f3a77e55d547c581dd599bad68dde61f7f5b2f9fb9bbb9791f48ac7d18d0d5f8cd7f67f9a0c607c000000b02a756690a7e6660712a100fae90f32e28b645f70f1b8c439e76837a73b07767ff000a1711532cdcdd12851eb4a66db81c93ddef60b717a148c176d040a7ca8d9c5c0fe3a435144e883016d58165497a2c523616b47d77909efbed55765190628be51fbb7808147a408f78bf69bf5446c2edc29e8a09c9c534cc621fe5ad93ea7954eab8a93e5bddda7c9e328137eb89d2800c078f7a719296fdb5042f641adeaeea0050525bf31376207f04dff69c20600000168000000b01753ee7a5cd7894f76cc4ccd81fa81946fa03d60b832b9ae5928409bcf1be2f2bfe8784bb7e72c7ce59a4fae24c1ac1172f6854e83dcd37077590f76dff208e21253c79ec94de4b139f8f25b231f3734b06d698d8853a2b5aff264185e9063e65dca515aec08ab170ace55dd165cdd7f07d874dbfdc2f7bd11ace2892dceb7ccffb284d752006ba05c6df57b157e82eb0c92956e82a956c26901efe3bc750727f24f167f584eb2feddb3ac785f0855c6000000b003103239b2f52287a1bc26457e0f304469beb7b328b62f6c09048b80d8139f43634b59e50924881c4f38aef3082c520505a2355483ac256b6f47f62dae3c044e40a0fd7914b27754219164104a4a431f2d689ba47657d8489d2d534f4afcd27cf9a7b1cc5b0cf4ed17eb0a5d9c2334a60522a1aa57d074ad133ef3b3bb5d6fd7fac831577edfe9bed2bb17a0590bc2d925724f46f8a73ca47ac3183725d297bf167a4590a402d853265f47caff62c02000000168000000b000dd75b6491051f8935bfcd680513cd6ca18d95dc6c30f0d45dbea8ec91d5b0a719816b8dded157c39bdad95fa032f0a2fea74258c60198bf3343c17976c6e94186bc12e29851c4ffeadb1fad6695390d271b1bf33e414974edc25115aaef98b3c933f3d0506adb72ffd4b2b853aeec8123719b96aa103abb947130b19ad4edab2857fead220eabdbf2a0bfd0d9edde0095733d00de26130b8807f29c49e406c5ca9184a48c29f0d3e231bdfe52b1095000000b006695840420eb5ddf2629ba523721467facef0e6f381d4f614442b2545f7bad2c075532d87bcf9c9916d82b395198d7851771a82571cf877f89a1c68620dfef720531f456303b8761567f0dbc59f0e1d92fced163fb459a742551c6cbd255af8c82a35415818f87ca8e9cb0d52b181ff0db732ce4a8bf7eb1364c2da8bb2c6a4ad22d8a939559e21e4dfb8f6294f58081b21393a87bfb0f080cbf81656cce77db7292249d80fb58838318e5587cb041300000168000000b0148de884263e33bde74d5404cc8475b2f035968ef21c72b4a01b8a543b0993a3eed18a0ff80c9d9be15c898932efe6af2161dd1a1d4a43d316925eb89dc4fbcac4071d81a455ab7358555e88a1f559853e4e4973e221ba36c9a09f9a47c4ccad55011f26d02128c5c6782a2201e5f7831bf219a1bcf7b1bbef1225e3888b23d7cd93cee4d69d3ad600a2c03129fe4d1207795b2498b5a2598864b573c52bc4d3ef9e5e1b1184b6a7838f35be61308d3b000000b00853bd6771dd1579d499a595be86a447bd9a76581dc7261a19b9c2fbf5341578be1428be3c45a211221dadb1c3882e2adf133e9cd6c319dc3d948affcaea75f6ba9af80a1c127f1c8fe3d68f697f1999b28e7d164e39a358ed6baaee067dff1c7c2ca6fc608655c9fc73ef56278d8efc25e7e9993a246395dd2de5cb458d0ccdd47f54025c4e29ee521aa8ab0cc7e60628329e1038c8b52d3c49a99148bf9a9db8ceddb7c2899834ad1aa5630b66027100000168000000b00f646cc5971c8f246cb4d5b9fb3156dd8d6261aef6860eb87240a7264d7c9e0aea30b543dab272c1bba8bb3e777ba26fadf584ac8a4630fe74693c15be2550185b54227892607d82553bc204fb44efe2850761b3ef80eb52bd08d62493a060432579c282ca285db329f8e748a77f56b90953b22f77cca03e9cbc6cc74b4c4bf99b19871bd188689fdd91b4d66d2bb9ff1131d15acc0c19e3be21aadce7e9016cf98811e18676d28d3cc5f924fddd383a000000b009092ece082b69133ba214df83655988c33be9f21d3c73d63e67c2cfaa34a871feaf3c93de30d360c6f1832437a3634dd9097ee3e1ea4200d39f5507e7bf37cdb979fcf0b86bc87ec73d34f9b3199ab1630aedbbcf806119953bc0e255757c2361be4c82806f2a1fcafdc093779e023a22849cd331c9ab9d7eff5bceaa17318dbababb01b8c52d783b99e4955a5d175a1f1c5bf9f2848499567950b2943c4e2a50c70ce6cebe04f2c3f679eed2af93d500000168000000b013386424c42b06faccedb1f985f1d18e0b063b397baa031221778ec55fea5d2842e84ee2e94cfa286773e10c9864327fb406f5237f9dd890e8ec6f46766bc312f64ebc29a6d70fa105dacc9575ae3e1ffb440b5e0b776b0ab000dd4e85efc7032e753806d65e74a5a267b14194f922f91e17798a352fbb5dbdf42a38f94f1a2aa6fafe33a56c573a55f3ab112523c8200a8c4425adf11b20ada5fc6e6c298a29703a81f69c836c2b86bcbe455fb3c567000000b01e6e0d2cf8d238b4013918d283e17257826b46a17df141e24f4b2b78a1b08d23dc785242a0074d5f4d317106e4a98a3524e0e48d7febae1f147409b1177e82cfc37dccdcc434512d3c4b6cf6be3a1a54b67587d0478ef6cf4423878464d4a0e33c85e1098588b24d645a0eb19dec8e49208ef4a81af41618ba319d7538fef2d8e5030ab012020beb2db1d6e8af60520409c87425ae226705f606c17dc36b8f455eeb3aa55d83376a177c2fefe7a691e100000168000000b02d33b0a574089ba846ef9b29652fbd89572b401286e47a196f42f2c59a72af345f820525a0f390959b894b7902ec9b3307391ecebc8f44c2ea95b564071ca9b2168964e235968e88c0fab913205d3eb0e99df4d6ad07d57374dcd759cffba08f0f9e80a544dd90ef3f78e90a4ec2db822af75219c5c77d9abfa1f4cd4ba1d539644036f0c0ce0b3e222e5bcbbbdd57f42b011ab0b05e070f65d8462226aceee775418e8a43706d65f6e2546cbb799817000000b0104c05c488b901e9e516db7628e6d255a41d021c33713eabf78dc207b004cfd4f4dc9cca5239608cfa6204d14664631ec4a03a4f56504fe3905275a99c8169a8152931ea6c0f17f4597e128efaacecebc156d6939edc07359811366863a0d2e348cd1ff96908d54f7c00dadfef30f2ba13679a3d2820117b827ad36c4aa5166739664d0c882bc4f754634109a50ccbe01f6cd7825b29697e2b8df7738a163c3ef9c91bf1b63c4cfb8b562892fbe5bcc700000168000000b02982c72e441c4042fa61d0133f192a52c0533a1838c4d1b8112b9161e6c78c46f8bdc3a89707b1d1ea733a8fd98443610648f63aa90bf8f3b9e2f7b486b479609e37972d0980641ff0fd998bb893204fd8cd6c0331cdb425c0f39cc7db8af23ac058e7f5b6994407237592be10702d20202204d083144509d03ad822d0456863beb964cf0ef4aa9e035887e73912334f0d33bee8566c3e42b5fa0eeb4a415a3ce7ec91ff68c2798d179b23999e3949eb000000b01e7aeea8d98f40f8287135344071c9cf65f26d7d5a4b166f8d0376c67a03bae535f5006ae64575ca1f3d648b3899b47390449e55c465d9c8f295d377725c727cce10ff1feba4682eaacada187883051719a185565c8bbbb8ba4a5f3fb166d467d98ac14bbe4ef27149fc5c762e77d3ca1cbbd5824f8c64602b4b61df5658f8aa5e636b2963ba142392977939dbf8c0de01d6d0511cd1d3c1d92827fc645178588d3288bb2894a09285d70212eb35705100380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01d5d78bc81fa611001cb6b8fdae34e643f2c0aeb3dc903824c650b7d30c5f30ee29ac7152718a92d630f59f9f1bc535170acfc8a0f4e8458c9606eba1df158d8aeecdf01d3b276ade863d279867c21c7ca1107eaed8ad9fd205c75e0ae8e227cb8cd6c2109df073479c9625af63eb1922ff9f469eac7dfe00c2b6453138b86cc8d610f29098cdae6d3d9cf02264d9aaa0f68c5222e40323d2f14ccf3a239dfaf5de240812b33cb80bde5e10c27fc3b57000000b00eb52dd8e10bb0e741613fa7ef4f6b70db1801a40e81f7cb6d32cf18c48e911d0c52c0fcefc23525f1ae04aeab5a08f68012a3e994f042a2a627bbe7b73d4ef3163c3b29b603f2e01d12b41abb1236f884495dada201f178a56ba1ecc80e68f6bf369f9fbff5fd8b984af328023ce4002e403403c9e4424441716bf5f80cf200fea87cdd551244d01599084a2c91e10810c7ba68523a9e67d9fb2409bf03e63b71a5f0ddea9f553ce997e679e10d2210000000b02560f23011da264d2204f45315574b9daf7d4f11c07845ebbf569fa93dc164d68bd293015f8fc7552dc158d319bdaaff32b391fea9ebc8deba4acc84ed87b7f4beb13fb878edda83d34575691c0d5ac88d30457026545fbc15b98de826751e6794c8d39d90a0d04761eb8938b20d75ad0e7fcbeea0eb8e96c8f746e6d0bac0d2cce7a3ea8903850abe81574219e6e19315dd9cd5780d5701f3917dd5e3989bc193c7909c3c3ad97382f42e6af9dadfae0000021c000000b017048eeecca50ffb16d8e3f8285d338ac89e17063109cb38f57000809684d3021d356f222f0764fb714acf38a3deb2142c6cf9f9de7476afc1d8e4e956ecca54b3ebeb7c33bf55c9408100bbd0ba4004459c4f3e3998eef6d2b0b826312409bdffda8e8fc5122e928ce578be2197fcf804208306181426768ebbd637edfae4704efbe485443fca4b6c14922c5d9e9c0b2f77d353b76e46ee53f416bf7e3a682999ed01ffabf7753dfe7283e71fb7e85e000000b02e0657974a680547dfd3c10f1265454910d4ed175aee39a308a40051f3d988a607b8a8dc21a8bfd34036bbb06f8324c3e938a5f0649654749d0c61ddf30a4fb8708a10bae59d60828efa75e424219b5394940f6afcb6b916861e7c27dcbdc5281f172027ddf69775329a5a95cd46d48a00223292cadab63ffff320e0d0ce82aefb31f062892d15fdf0953546d364639b12fa458f9b60ed0a0d39a4fdbe6e2860b7f62925637bef497f141602c9d270d7000000b00c95567e2e6094fc3037ccc632eb4e0f69b0ec9add86535b8975cb4592babb2524ee598e5b4565e01970a95c927671bb09fa7a6c8dc5fba18bf9391c3b14e76adc17bf6c57c18dd8f42c5a5c6b894b222bc4e273e359029763b42aad8cdf5162f5614478ececf308adda3e27912edcba1521a52b1b61d042edd44b7708865870c151fd2e98ba40768875bb261b06f9aa0289e61634d7c2591188d43c834026f3eea9f591515c40fdb85e22c54ffb31f00000021c000000b02b32adae3f90e17a53312e259b5debec02bf85d710a415fabca8fa12a1043be8799835971c32aaba44a20964709b4a2c95f73ed24032992899c2b85a61d16aab542ad3a5198178205b6569ba4fd147a898b9049c1b211c9d6ef20ae300354b18b909395562a8d0f16b81e278d9b020181700d26c70f9d082713bc36024dbc3cc50a77070df6d70a7430981e90c6c872f04917fab37a1eddf4ccd75b775d96e673f1ed6b2ea1e28d783925d4824eb6598000000b02e2df3d39950c87b85ae8e8cd2bf4823cfdbf852220ef78741497859e0ec18567944671984f448a83a7cc93eb14e59daf5baa359889699c2597e8b15b1042860ea5c1012d8dbf27dd26e0e7bf7071c69949fffde11e2662bb0cf0932bd353768750dfc6b958858850af46778d6a03cb901b5e19cf809c63fe434bf5bdcd6a9008cafb74d9b6187030c456bac2adbb9a2235b108d24b25bf193061cbd833af49adef5cf5c3cb08954366d0e072e796484000000b02065a49180d6081e487dfcf907be0623d141a5282c794e099a5d9600347984f28861ba0df14fef522376d2567ed7db008a9e5acc4155faa1c2b31387c5536d13bf7914e50925e6f2af59bebed6c924e44df66424b81d5a3168360c6aa9593ce4e5627c1af04e059181a0c27a1cbb02b20deb2dbc1e99e193074c83a905c0e903182273ff4977e203cd83ecaa703016e3089de6bf71fe0021ac3309e1c1acfe6726d954b37e135c2e101a1ce617383bfd0000021c000000b017011d0c2744ea6af214591d9fdc347af720aceeda73ed8897c959fd9deb830e910537df01bd987f76f0526c7d45d957e88e1a57814509b25716796cd0bc6f412f82d649918d8f7968c7cbdd70c6f3d17df3fb92053e11499dd54c7327dfcb66be361e99b7d839f56d80162037264aa80de5f6ad2622f225a2dd1791ec92cdfbe457628568fcb1b268d52ae4b4f19ffa2d371eeb88db0e8799d3f4443a1ca82f373eca17c232c288b1363eed59d952eb000000b010502b80d750da505bd79ec279c4eb11d2891cc905b9996d9c4b0f0a359edfc51bab8138e6d7de86c1f7e337d605e000fb005d95d643e44f4588905b58f6aadd6a780ca323492999240e4057166b816ad0f51a25497fb6e27ac083abdb734ac1c78f94892da418343a24456a09aafbc227463955145858de7a2f4fecc7bbcb2e22b1bc11560b7fed1d328a7e1d5e390b2b2ad74dec66249628277c8f9d12f07a02f8ae872628c2145ee1385c5497e9f3000000b015b65698fdca8ae228e489b4b929a1ee3b963aedf3017dbd88fde0a3d805ee9fab109c0a8f8bd1206ed2ddbe436d8783f1edcd9abc543a4bb020b3a0ccba5a899afb702d4b3951f377b93d9f6469186cfd68e32a291153bf3422e3d4e37266726e6a683419efad3bd9cad30307ac2fe8211c4d0dc4a2ab91050344a0542696caad994403bd01ae0d13a9565abbd53f0821124009132de1ebaa4df545b36676a076435775d29a2235d84fc0b825637e030000021c000000b00b6ad3057200b4e404890d29e8245c9bd17f34e90f2a7b8fd3ac0ba9de5d446620761ea4bdd3814ccf831220f6a8dcca11b7d125fac4de4e78d90c429eff8c3afc2f465046afc77aaf49128dc446b1758240bbfdae8df5bb7836ca67a94446c2bdc7dbbf3cc6e8f9a6d4e63d4b3a830e2d2f00e5b59aab3bce6b89c80a3a7c474cb3db989750938d6551c4b4e994d20629b7359e1ccbc1653393793ecd73d77ed07ff479f92e53a792b09430e5ab6b9e000000b02fb340deb014481eb696b268035047d0372997fae78b350d8f18c124f52edc8c2a9e5f20cb1b4d8ef7a9a603882634ba96cbf1525561a269ee61fb72a5e19632d3f7d4db01a4cc1d46f77868a4d6d67d2e89f84ff715b000f7107f7808938fd76001a8b939b72bf74a0cf0e5559db64317a16f0c9c8b30b188ea441d2040b1d80da3227d844f460628653a7d2c46a08d1e3fa9bd137c1be0fe20ecdb426656150012adba2c38a6f6ec2bc26d65aece57000000b01cfa2baa186401d2397f8c793cf51c4cb0c712881ffc5aa577ab92a7ccf097de4ce47b7b6f3e469658bd2ccc0ea316da37daf850fcfb6857aecdd29bf157fcc5695b2a49570b57eb709e9c6bad68a2b45be3ca05078720784e6943a67aa6b66272204a27995934292f72f6b31fc9ba3f0359142115148b976ac6b4aadac6b630606493c552734c994f8c97494d1dc8f713410858895b326d2b121eb7fe4d945f8053151d91b64e90197b1c8f4198e4e10000021c000000b02ff761f6595fa886e09cf424619abae559979c4e8010732c48307171260d5dd20193a8e799ce49e262a6f40e89802b7fed056207408b639ea41637ae8c946097a5d491e82b7f330ce9980d49fc775408ca5cd241ebba6da7447259336deb8f3a2fe4180273d88d638c25fc0f1e78c3291ddc95b0bc47139c9b0252ba62812ba2679ca7d020b07b13c09a1ecf37e9def4298af73a41669cee01dd0485ac91b042447fee19ab55d70960acfb6af8c410b8000000b003bb160e7cb6180bfbffe000cae25a3f6ecb3abb7c3b50f9c891ce9ea20908d9089d6271b41fb1a8741033fd836f3ead284a9ca1cecbe9aaec451653df92ecf8d91fe22bddd602ed7ecdecc004078a9d4c4a02f58255a74d92b41c527d299378c28d191f27f15cc594f3eac7b5f114c32d1c1a990d916f7d2587b52dc3455657f8aee2ab0a4b34e8e97f1c39e2a5d28e108b8a929f70ab28104c8b1e485511c34a9632ea78c96ed0b44cdc6204e38928000000b007437dcc18d8abb45ebac4b3155beef0ef31b6da00df7f0391202d65b569aceb398291fa73226b3f783039213ee06a5cfc51ee49a2bc9de45508d9b7102e5e6a33583c96ad0d9843b9a7b9692aabd29aed6086ef150be502d32fb502bd078f15db194d4ba7ede6fb734f1e2ed3b4a38c1e513b9bc1ddff6885cbb42311566174f1587117429b43e234120c8a44f1d2591b017fd51b1b6a6b828dda14dc7fd48c92f8a475823aab9a749ad929c76f14090000021c000000b01fff6471261f214a56abc56d36c3954c0797e0259a781358e1d7d21f612a0330fecac455da0d380fcab3f80c30964f59b5abd157e70f2a06b716ed3aca0f952773204b240ed5c723af529d943366f4fece10bd5c7dffe86b62f7c086a6b03d96abc70f16e442dfd37a9d8958b61db16b2c16f75d5664c9a161029ccafa730fdfd2213b1453bc7956d028a445e3ed7bb20cb69ddac980160806b5454501b2933198816cb9cb727eab724405a507a63f4b000000b0223be0f4882b58f9555deb567509caf52d557f7b2f6e3fd0b2a9bf2f7f1f2b192d9f2532c3c6a47876c9d676773d3ece33e93a70064bccab377ed327fe320c7250edd93cefe9af646577e188e5d1b31b9690ad8e6e31ac164ecef92ca20645893f5606275fd553929a2fc38f289fc9ae21c180cd69244ef85cf5da8c597840790ea9194c50dde875c01c506067a9c3e513de740d6304dba81fbb1ecee1290c564239096682d049a82d62577ba9dd0db2000000b01b2652bfa98103d0d6f788c514f03b03c14c48ead330e04a96c237b6e94b86f53eb902765865bcbc79e0f077f24a2a952bbbbd490d1d9767ca09fc8c56f10517e217e5ba5cd702f71b866d040d4b3e5feb3d937e5b9048badd3123c8528c08d9140df178657ad779acf64977a35bdbcb0e4672f93a17f5f91027ad163f623ab619cb1943efd7311bf437e669b4ed719d1aee62405603709fcf117258b136dd58ae612c2a326e7c52b2ddcdefaa82976e0000021c000000b02d5b753a8d04975f26c05803c8c2d910ec016f525ffde074b1cc1d8b2ef241a81d58bffa52f2255e614f8dcca690979c12b80c26f1b3eef8bcab65720323fcf2c8dca02c7560bd564289c28111f679b8cd71aa1d7c27bcbe86d4cbf397376a075d495a0ddc41752ae41beacc8ad4afef066bce5d0199a91ceecf7ba5ea8cebc9375cbbbde5e394395f0d2ea3a7fb295a188643ca8ed1a80539429ee11fe02cf1678aeebbf477593a4df8618cacdf831b000000b017c8c4ce474e91560848b41662c29ddfdbbae1b53e535a6036c785374f7b0ee103594625f1ac250c0a3ab476bdab0aa0d9cbcdf79ed1d69dc968da8853c56d3d41f13a404d65d870b3370d54fc44d6136494aa6650418c215fd790c1b956c3528790294367d2387499f46ede3fe7513d1e014f345880fbcc708dcbaac6ac50d7c7ffeeb59d070ee43feb94f7229e18812aa86f7735716c43f97466291a70762aaf26547f3445bc5a7aea9aaff389fb21000000b00e661a74c75f1167a93477bd56a23e49e475dafeaddd5360d7cd4f2cc59202dd9464d8191d73a9a464c829ad430156137f77ddf5956cd0245a8c056a58465fb25e22905b58c9941eac48bb336d0e6c5b8778fe684301025d30cf98730796081494f1e5a65dea1e72777b09462b71b69700f8fd322b262a54c8bf673a23477cf66ecac0ebd8c173af8007c98fcd965a5f2ad3639804d82b6296221fa928583aa08c53fd404ace064d3559684f35639fb300000fa400000168000000b00ead6f026e928ac8a0795ab8ba70dd4d6a64265d6f0ff5aa99a13f573eb4b58f460b05e1f43c97dc1a5c8b081e92431f72fcffb85f065ced0e341fa63085b790f230c93c1694fe079cae7b9c336adfbc3e2f796cfbf37cd8bd73cf6336a4154094dfcb0b56d7af13aa9cfe2ab5a044e32a2aeb5b31b53d3e1ab665c48db90dc578e455d28081c1c00dc6356c46e8233706bd95ec4255176ee4497e06c2cd2ad44ee820a4c63dfbbf9e73ca12e70d5653000000b00b2fd7c3123627072e1868c126a231dbace4ec63b09a35812e11541ad1f27b6c9d22edaebbab313c2ec3a06029b585ca3b5f5b2645058c53edbda6fa6a037728ace7ed5bc484a8600f1779d9a9e52b6f0afb13b5278c4b2cff0d5a2fa30ad7f54aa06c7a07dab691f1955355c39f4a7b0f736fd9e82a3177365440d351de3d6cea622e3d60d93c1a03f5a494c4c83c262881e84eeffeb6dc610182686cbfa67767cc93a4dd2447edac207c777934d86a00000168000000b010585b454da2703b4c94fbe624494f03d4b3cdb892e3b2b37f2ba2ec915f41412263499188c1248797cb5953b909079cb6191f672905bb980b90b6bbb8078bdc0e5fd5a5d08b4d2645511e0e4daa58bfc4c47ee88b24fc4722fb2a9d1939641c9f9ef66ff57fb1057aa8c69382c899bc13a2149c82abc286525376ee7e1673864249635178bb523bcf6df89f142132d418c71174b1e71c5542e3b50d593c5e786ece68f2373a6bd627ce0f6610f212ac000000b01676745d8548f8ac38840fb4b66190835f02bc9f920834068cc0db19365fb2a238fed65d0c90399f06eab34f1650b2f659c701117333265c3cecceba04c1e9e02230e5211b879ca60ae5fb0352ef5b3449556c931fcfe9fc9937e8d1d2bb5df87be086ff54c42fd13a248ab2dce8cbe010daaef37d0a054b4a8e657e10b0360c5d3b2337c01930bcdddfd5234c50d298053184bda7f3d523ff7c0ebbd0cab64b56ca7e5f093744e71290a32604136fb500000168000000b0287e158dd4a3e203df2e26175c33d34c5e6668d64ed9cb672fcc591ab18d0d3eeb2337de1bf1c7f8c95baf5f91fee9e03eed0fefe6c371042d26b2e035133954224c5a8cb9ade7375a748093214fb16ea951ff27d68e293256522c4833264b62b43e870bf80543fc049662bbfad54b650701bd302c0dff752e98b9206ee82cdf78e51fe9b858258cfed7c8d1b57052122c83b0ead5ecdfaf8ae6dfc5aee288b45a8bd05553e6ea6a19f62c40de7ec3e1000000b01566c8c0a9ed2a3f1334c63984568f3aedc883740269434fe81ea82a5238b1b91f542e2c33359b98325f24e2b1c982f905f909ad6b120c00ac4d33280ef0aedc5a01e8b19aeaafe11059abe726896fa722cbb1aa39f70a6f871c7c9dc547c499d5e244e0697bb1d0700e93710fdd9ee3286755e586db0ead3c65cd9863e360756396d14ca321342605b3c23081f0377f16303c0ea6da57d1d1175e6b849632586f81dfcce23c4eccc06eb527c2a6056d00000168000000b0012c5c658d79f510480a67eef3b213505899e5f15d41407cb13ca717b3ff830dc26e37049c474085cc5fc631475eecf4e45e299c0beb4ae7d1a7fe9e58b3afe3e281e48625cd9f2910f14faa5228579edd8f34fe94b561e1d04e7212edb7e80709d3cf12d0c533ae4e128aac67995fe82439fcaeb84ddc6fdfb18c6e4f95548699c727e7eea5cc91ec967dc2bea6a71c181e2b7ce58a1ccf59a210087e701b27bf39a12d4f0f07a3e50c1b12089d31c5000000b005f9f9d7569a1767e4816818401a78bdce0cdcb9d8b1ead1e69e917de53d0f8c40722e862602044b326ab661a2fba40c5f4bbf95fd4d41b81a7a5ce08cd200a8bfa7358aa144dc522750f972160f2065dd557256803698d0a189fdac6efb47c24c7e6b86a490e43d04586180e6f29af416973e174e5b19d0c500b80f0d8f38133ed9cd18c3247da0ac7d91ffc86373141b500e43a187766974e1031939893c607f1fee1ab0b0771d09d0fa13195fcb6c00000168000000b001657bed277f927bc82c8c47a7ede9a6aecdc0ed156b200750ceec3dd1f30881ec8e00f47737369279f35763d534ad13e838c9b7c3a722889de57899a67ad47bee6be1588e6ffc4cc15792e14ca75772906b655b7d151889fc7410bc560d348ec2a140ea96d16615b0a7b0edf8fe9af21bc7b7c2abb65dfe2dbc57889f0b0676d51dac92635040769ef5f66d5628045c2cc2289b0b6e9a155e8d5d65ce7e44bcf867117604c194edba0c25482a6891cb000000b0128e7e4f84f256e7c7150bf0efbdb087548442b83040746755281ba7e40cd57c6dfe2b95b707a2a5176a225e3fd22a3331fa5fa56d6408ad9904730faae6aed6992de2568869df81cdf725f6684b995b79a47acdf81c1d86925be3501e0cd971b13cfe80536b3d8cd7d0182aa825122a0663138da5bf0dc9ef7cdb6ac102701f051ccaca9b649c1bc1e5f2d201364b4e04ce71f329ca1041a9346b1fec964d3d93d4f5a948393e5c43b4f858f0a82f9700000168000000b0109d0ae88c48e69b1a27837f76e8f69e9b2056027c665165ec60616b71063d3397f0758e18732a258b4e368cecd1b8402d8393abb41ebde25e46a21e17ccfc44f727398fa0bdc017c52eecb4b2ad7c190a014c0991f338f58487f02547d8787b3c6986293370a9a1612fa665848e9f0927697b9e469f4ecfbca42d9b5483178cc9808490b8be4563efe40f8ecfa7b8c91076b6ae5be2e5c1ce93d5c2d44073c44030b3f293e667bbdc7a3569d17af669000000b008d92c9c52f2640a911de46a5b93970513438f39c118e4570b8b1ed28220b148b30a18c59cb7532a9fef2e031d54f621d637ef8ecf3687a2df0228fbfacea2d6014faffccad628fda5228d08376599fdcecaba8c4ae16c0260370bf9ad7c1f38f2bd4499e7be5ad84884968d886a06b82c8ca191aa13ba167436f0349b046521748423559105e4e4d45a73a2d9d2c36f177a85d9cb5389b958950498b9aaf34291042741e71d3943e5e032d7503542d100000168000000b011b69be3d3ac007239976a276f066e1a85c6dd5a9259bbbdf37422124bd80284b90d2340b2161c2ac33e055e1efc0428339aaa14ff06562a1fac87a4629e2b03ff48fbdcff25e53579312d9ec883a235013531bac808be9bd2afa3f3b2d1bc2d02a4a5c8a9ff0a1f24ac10cb5e987e6912f52cd692bbba05f7b56d7abfd91ef3558a82633755768f8d89f76e7ef1806915c81f3982a45295f8a3206e4fdeb07d6248119a2ad44aba387895f7f72ce170000000b022c08480fd3b7372aaf10b90eafd7e51e586153eb3b978b4d12353fbf94067d0f88e30de469700dad2272ab223d9f37307f0bb29f5258d68dd437b8bf1861a5b66a3ea70af713a4523d99bc62ee5bdc2be1020ba3a9c87f768029b27bd8de6a08f240f21d97e8e346c6bee8443ae61fa10f65ac42259a8425e3baa102ce6ccc8970620375a1c870b0b158c2b403bdbd20b8cac1cd408b9dfbc0d605656299a3ea94a645169f2312ee6a7a221513b99ab00000168000000b02a33a1552316b3a361db417ea6b7ec8894b574f88b9d997c62af1b7cd3e4cfb7aa0702d3b4cdbd7b590f0a7957e7853bfd1702d4de758bc456b4eac59e4ad897ff328404758f961595858c6d0aad077c896dd2dfb4f11539ea3c1f6e05a2f467f40e6c47ef7c04e5e50ca282957fab1b032f51fdb416c4648e41974b4240f75c7fd5d0c90c58efdb90058b3d8091dba917eb391393030a590a26339fd846f336db1ea686e51905b51bf14646cee0e1b2000000b001f1bdcbf81655c2d15afa7c6c2d5920ae331b5a695494df52eb97110bb983926daad43709a467b79558be826a3aa1c3283cbeca84a7afc08ecea2999ba37f4bace5348315a2d889a92c3cf98f9627f60661f8289720d7d11dbeb1ee8ab0cb47247c33084a182b9d98c2417d48a6cad11ca3532f891e8d36d50bc956e5d5bb9e886d100d98900c31cc5630201d002f740cf6d9bf067e54c866e4f9f047ba1ad403fec6c0eb5407fa5f6acdb7177a462f00000168000000b02fa0ef8782e13d0f97b830382661e6e1364362fd22b7246b707939ed53eb59e5bdfc76224ee0aba2150a2dac6b57f0cb08f6af0add9be83e4b59a1d833f51aa36e975bc2ddc135b9ebca78161fc0b4e2ad6efcf2e3b3dcad42be72868368659933aa7139daeb68342d35fa389687aff3162a408b08e27363cb6eecb3b78ce1e4f14448c04d2dc426b3e03b1603f27a951cae35f37d423df829370ea5914de588186f0bccc3615731d0907e20b4fb8815000000b0082608ee27cad407c4c981b85e8e48e5f16979b404e0b1d103e583a3efdabbcfc83f41d287ce3d2d289bd487311c444de901ed841f739a1b2fba5c7ca7dc924479f3cdfccd796841b33b2e7866c06959023cb3a648b1466dde40a8db1c5a6e114f299e68d75cdccd17abaf0f471e678217a1ebe7c5e27aa118b065b2b06ab8b14c2ec2fd35eacf41695dba5511cad6b628fc03ccbf84ebaa531297d71b5996a63ddb06ce45f649423b88301e50778cea00000168000000b0070132147a771d9c009258d0babdcb0df251f4a801b3bb149bd50be96be212c79f326e13a72c8410fbf06dab6db66c3f961a9e1fe3c9b413ceeeabd91e3ed8b2b77227ab9df51b04bb367c792dc93de2b5000377f6aa4ba761afd242964d3e6eaad6c478697dd1e4217adb18d09293490a4cc265f939ffb89596b0b4f82eb1963cb5f22840bf3b41e4d4435ddbe2125e052e834d2dd41183c8ff5b18c2dae958a689e3b0e162993f05e13db13f479909000000b02f0f6ddfde294266d182921536b3214f77f7a8b13526bba68c578edd9e2e8bc816a3e59064ada280f94cfdd7f51382b4b89606a6e8c443af85ad5cf2a7a3a608282c5d62603b0e6bf98c193859f15fd5268ae5f7ca56122f3ed04032892922958ce7555be6917433b365d23ff420ce151208f216bac3d8fd85078011c2bf87e7c3ebbf5a70ab8f819d3887fd6048a7d519a8dafe508124b1a2352a304d1c4b78845abf92b774dd8776859c7ebddb870f00000168000000b006b6aaa1844e8005704b1496693b6777c4afb0d63565fe55dedee467070336b3c7e05724bc8c1b5daccbc314bac11ebb47ea8948087019b458c4a000aef28747c02632c76d482f953c6220bce25ad9c62be681b4423b50bd54fe11a04dc2672eb8b493f4d6b64486c3ed35a55843149d054f7d1dc5758a961aae6d81f152ccf6bf573a8f26b0f5986cdc5eef771a17c42207445af59e2b05631d72c8c89b42166a23cb09e7d09c4368ea0bc28da133b8000000b004cf95c8b3f9cf667214a5107c4aae240121dc412da5040db710a70cf45c81d33dd39f67b23b52444e040cd1064c1a526efe463a163adae7238365c3358147d26aa6b9fddd422655f7e62731b7fb0c6e209c146080a95d29a4f949a6e196f8200762212a288eba2e286b7abbb95933500c63b6e6f0b699fb4f95e481e42bda165c38730836f56110859416b8da8c88972cf1a79f33f261a7d7b8e2866d59cf4420e87951ec51007e8ab4829496b5048d", + "txsEffectsHash": "0x001e043fb2c5de8d7a5caa2aa833e839b166cb0b2a03b1bcfa96dd224823c8b6", "decodedHeader": { "contentCommitment": { - "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", - "outHash": "0xc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc", + "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", + "outHash": "0x00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb6", "txTreeHeight": 2, - "txsEffectsHash": "0x72973218cc03166a5ea58f3b9a3ee51ddc7c73afca1d69e0db36abffe6ed00f8" + "txsEffectsHash": "0x001e043fb2c5de8d7a5caa2aa833e839b166cb0b2a03b1bcfa96dd224823c8b6" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xa23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb6", - "feeRecipient": "0x09cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d" + "coinbase": "0x9ede22c45cae1d9aba3dc43ca9a4014868dd9416", + "feeRecipient": "0x1db11c308c86c9548e554e8ea4ab6a0e7c0715098a8e50d016c9a7d2cf3af8b0" }, "lastArchive": { "nextAvailableLeafIndex": 1, - "root": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f" + "root": "0x1e3523d3bd50ae6204e1ec2ee1bdf8af4c6217ec80900052d2cf4259379dd130" }, "stateReference": { "l1ToL2MessageTree": { @@ -77,7 +77,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f00000001000000000000000000000000000000000000000000000000000000000000000272973218cc03166a5ea58f3b9a3ee51ddc7c73afca1d69e0db36abffe6ed00f8536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb609cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d", - "publicInputsHash": "0x128058d98f9ea20e35bc53085a25f52116e86d382739af5ed7772e7e9c9de181" + "header": "0x1e3523d3bd50ae6204e1ec2ee1bdf8af4c6217ec80900052d2cf4259379dd130000000010000000000000000000000000000000000000000000000000000000000000002001e043fb2c5de8d7a5caa2aa833e839b166cb0b2a03b1bcfa96dd224823c8b600089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000009ede22c45cae1d9aba3dc43ca9a4014868dd94161db11c308c86c9548e554e8ea4ab6a0e7c0715098a8e50d016c9a7d2cf3af8b0", + "publicInputsHash": "0x0071ce1c49525ee1f26bdd38498fa26e067a3596f7a80333a2546fde982d5fd5" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index 50c8a7f569d..23e180583bf 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,32 +34,32 @@ ] }, "block": { - "archive": "0x20faddabec4f3d554a2250c996305a688945c4e94cbac84b58b74b049623c616", - "body": "0x0000000400380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b02c0376de2367c11411713c315236060fc1788500f9ed6f10ff770973bc17306286410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb61a39292d2ec1e376d77fa726df0b06f2fd9f514f64d8352cec5a6b69dc12fb8520274312d5a3d800957ad8d5056eb151e992628a9689f3239d63f56d26bf0d24000000b013579001ddbdf311510dbd336a43572e4910e1a546faf65a7fbb3becf6c776dd8a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb6018d4250e9181574171c2828f71858118537adf3b1e5bc766c9e9de316c34200077b5c368ffa09fdd51759d71d7c0270712abf2ee3977a6d1da827e6616f539f000000b02b0ff7987945c53848fa83ec03d200a9f8dd26920dc1ee3543e163fa2177bd598e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb61945a9e7849fe79b0f08eee190a7018d3503f2e078acb45130c4c5f04173887c1f33c3cd2b81dc24cd04208fb70aabec20f7041baa5e7247e1ce4ff38c1f9a1b0000021c000000b0126410bc339bf735889704ee1bdf51c8807583365acf757ec42596735c2803d492410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb60099c30b3ef619984ea56fe3a8b452abbc9c4f84c5ba3b9ab108f8697c23cef70687dcf0e5d80e220ca0a191cf17fd0aa88f60bff76bf9916212826cc6cfe096000000b02a1c7852cf23c95c8083cba6b56dfb443041c82321966d59884bbe8086d84a5096410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb618522aa1da7debbf4692369c4242fc276c6894718c813375752f2076a6d415731e404487815fe049048d684a68a6a686585ba5acbe32f16c2638aa79f1802712000000b0117091768979fb59c0204ca8cd7b4c62b7da24c76ea3f4a3088ff0f9c18890cb9a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb6300a92387605bde63e7efd54dbd1a5a31c34d95e53482b5039554883d1845bef05945dab3bb612464429e94c80b3f7a4dff402510b4078b5a67cdcf32c306d8d0000021c000000b02928f90d2501cd80b80d13616709f5de67a669b4356aec7dccb61906ec38d7479e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb6175eab5c305befe37e1b7e56f3def6c1a3cd3602a055b299b9997afd0c34a26a1d4cc541d73de46d3c16b0051a42a1208fc0473dd20770906aa3050056e0b409000000b0107d1230df57ff7df7a994637f1746fcef3ec658827873c74cfa4b8026e91dc2a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb62f1712f2cbe3c20a7608450f8d6da03d53997aef671caa747dbfa30a36e4e8e604a0de659194166a7bb33107324ff23f1758a3e21f14f7d9eae737799190fa84000000b0283579c77adfd1a4ef965b1c18a5f0789f0b0b45493f6ba21120738d5199643ea6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6166b2c168639f407b5a4c611a57af15bdb31d793b42a31bdfe03d58371952f611c5945fc2d1be891739ff7bfcbde9bbac724e8cee5dbefb4af0d5f86bc4141000000021c000000b00f8992eb353603a22f32dc1e30b3419726a367e9964cf2eb9164a6068c49aab9aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb62e2393ad21c1c62ead918cca3f099ad78afe1c807af12998c229fd909c4575dd03ad5f1fe7721a8eb33c78c1e3ebecd94ebd457332e976fe2f5191fff6f1877b000000b02741fa81d0bdd5c9271fa2d6ca41eb12d66facd65d13eac6558ace13b6f9f135ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb61577acd0dc17f82bed2e0dcc5716ebf612967924c7feb0e2426e3009d6f5bc581b65c6b682f9ecb5ab293f7a7d7a9654fe898a5ff9b06ed8f377ba0d21a1cdf7000000b00e9613a58b1407c666bc23d8e24f3c315e08097aaa21720fd5cf008cf1aa37b0b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb62d301467779fca52e51ad484f0a59571c262be118ec5a8bd0694581701a602d402b9dfda3d501eb2eac5c07c9587e7738621e70446bdf62273bbec865c5214720000021c000000b0264e7b3c269bd9ed5ea8ea917bdde5ad0dd44e6770e869ea99f5289a1c5a7e2cb6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb614842d8b31f5fc5024b7558708b2e69049fb1ab5dbd3300686d88a903c56494f1a724770d8d7f0d9e2b287352f1690ef35ee2bf10d84edfd37e2149387025aee000000b00da2945fe0f20bea9e456b9393eb36cb956cab0bbdf5f1341a395b13570ac4a7ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb62c3c9521cd7dce771ca41c3fa241900bf9c75fa2a29a27e14afeb29d67068fcb01c66094932e22d7224f08374723e20dbd8688955a927546b826470cc1b2a169000000b0255afbf67c79de119632324c2d79e0474538eff884bce90ede5f832081bb0b23be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb61390ae4587d400745c409d41ba4ee12a815fbc46efa7af2acb42e516a1b6d646197ec82b2eb5f4fe1a3bceefe0b28b896d52cd8221596d217c4c6f19ec62e7e50000021c000000b00caf151a36d0100ed5ceb34e45873165ccd14c9cd1ca70585ea3b599bc6b519ec2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb62b4915dc235bd29b542d63fa53dd8aa6312c0133b66ea7058f690d23cc671cc200d2e14ee90c26fb59d84ff1f8bfdca7f4eb2a266e66f46afc90a19327132e60000000b024677cb0d257e235cdbb7a06df15dae17c9d91899891683322c9dda6e71b981ac6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6129d2effddb2049893c9e4fc6beadbc4b8c45dd8037c2e4f0fad3f9d0717633d188b48e58493f92251c516aa924e8623a4b76f13352dec45c0b6c9a051c374dc000000b00bbb95d48cae14330d57fb08f7232c000435ee2de59eef7ca30e102021cbde95ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb62a5596967939d6bf8bb6abb5057985406890a2c4ca432629d3d367aa31c7a9b93043b07c201bcb4949b1dd632bdd2f9f5483b3fffbf4e42084dcf1ad7c73bb580000021c000000b02373fd6b2835e65a0544c1c190b1d57bb402331aac65e7576734382d4c7c2511ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb611a9afba339008bccb532cb71d86d65ef028ff691750ad7354179a236c77f0341797c99fda71fd46894e5e6543ea80bddc1c10a449026b6a05212426b72401d3000000b00ac8168ee28c185744e142c3a8bf269a3b9a8fbef9736ea0e7786aa6872c6b8cd2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb629621750cf17dae3c33ff36fb7157fda9ff54455de17a54e183dc230972836b02f50313675f9cf6d813b251ddd792a398be855910fc96344c9474c33e1d4484f000000b022807e257e13ea7e3cce097c424dd015eb66d4abc03a667bab9e92b3b1dcb208d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb610b63074896e0ce102dc7471cf22d0f9278da0fa2b252c979881f4a9d1d87d2b16a44a5a3050016ac0d7a61ff5867b581380b2355cd6ea8e498b7ead1c848eca0000021c000000b009d49749386a1c7b7c6a8a7e5a5b213472ff31500d47edc52be2c52cec8cf883da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6286e980b24f5df07fac93b2a68b17a74d759e5e6f1ec24725ca81cb6fc88c3a72e5cb1f0cbd7d391b8c46cd88f1524d3c34cf722239de2690db1a6ba4734d546000000b0218cfedfd3f1eea274575136f3e9cab022cb763cd40ee59ff008ed3a173d3effde410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb60fc2b12edf4c11053a65bc2c80becb935ef2428b3ef9abbbdcec4f3037390a2215b0cb14862e058ef860eddaa72275f24ae553c670ab69b28df5d93381e51bc1000000b008e118038e48209fb3f3d2390bf71bceaa63d2e1211c6ce9704d1fb351ed857ae2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6277b18c57ad3e32c325282e51a4d750f0ebe877805c0a396a112773d61e9509e2d6932ab21b5d7b5f04db49340b11f6dfab198b33772618d521c0140ac95623d00000fa400000168000000b020997f9a29cff2c6abe098f1a585c54a5a3017cde7e364c4347347c07c9dcbf6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb60ecf31e9352a152971ef03e7325ac62d9656e41c52ce2ae02156a9b69c99971914bd4bcedc0c09b32fea359558be708c8249f557847fe8d6d26033b9e745a8b8000000b007ed98bde42624c3eb7d19f3bd931668e1c8747234f0ec0db4b77a39b74e1271ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb62687997fd0b1e75069dbca9fcbe96fa946232909199522bae57cd1c3c749dd952c75b3657793dbda27d6fc4df24d1a0832163a444b46e0b196865bc711f5ef3400000168000000b01fa600547fadf6eae369e0ac5721bfe49194b95efbb7e3e878dda246e1fe58edee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb60ddbb2a38b08194da9784ba1e3f6c0c7cdbb85ad66a2aa0465c1043d01fa241013c9cc8931ea0dd767737d500a5a6b26b9ae96e8985467fb16ca8e404ca635af000000b006fa19783a0428e8230661ae6f2f1103192d160348c56b31f921d4c01cae9f68f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb625941a3a268feb74a165125a7d856a437d87ca9a2d69a1df29e72c4a2caa6a8c2b82341fcd71dffe5f604408a3e914a2697adbd55f1b5fd5daf0b64d77567c2b00000168000000b01eb2810ed58bfb0f1af3286708bdba7ec8f95af00f8c630cbd47fccd475ee5e4f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb60ce8335de0e61d71e101935c9592bb620520273e7a772928aa2b5ec3675ab10712d64d4387c811fb9efcc50abbf665c0f1133879ac28e71f5b34e8c6b206c2a6000000b006069a328fe22d0c5a8fa96920cb0b9d5091b7945c99ea563d8c2f46820f2c5ffa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb624a09af47c6def98d8ee5a152f2164ddb4ec6c2b413e21036e5186d0920af7832a8eb4da234fe42296e98bc355850f3ca0df7d6672efdefa1f5b10d3dcb7092200000168000000b01dbf01c92b69ff33527c7021ba59b519005dfc812360e23101b25753acbf72dbfe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb60bf4b41836c42196188adb17472eb5fc3c84c8cf8e4ba84cee95b949ccbb3dfe11e2cdfddda6161fd6860cc56d92605b2877da0abffd66439f9f434d17674f9d000000b0057aa502b5c8bc24413419b2f29ec0b91e55dccf2d7609c5b232eb035c98c68702420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb62414a5c4a2547eb0bf92ca5f00f519f982b09166121a4072e2f8428d6c9491ab2a02bfaa4936733a7d8dfc0d2758c4586ea3a2a143cbfe699401cc90b740a34a00000168000000b01d330c9951508e4b3920e06b8c2d6a34ce2221bbf43d01a07659131087490d0306420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb60b68bee85caab0adff2f4b6119026b180a48ee0a5f27c7bc633c7506a744d8261156d8ce038ca537bd2a7d0f3f661576f63bff4590d985b31445ff09f1f0e9c5000000b0048725bd0ba6c04878bd616da43abb5355ba7e60414a88e9f69d4589c1f9537e0a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb62321267ef83282d4f71c1219b2911493ba1532f725eebf9727629d13d1f51ea2290f40649f14775eb51743c7d8f4bef2a608443257a07d8dd86c27171ca1304100000168000000b01c3f8d53a72e926f70aa28263dc964cf0586c34d081180c4bac36d96eca999fa0e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60a753fa2b288b4d236b8931bca9e65b241ad8f9b72fc46e0a7a6cf8d0ca5651d10635988596aa95bf4b3c4c9f10210112da0a0d6a4ae04d758b05990575176bc000000b00393a6776184c46cb046a92855d6b5ed8d1f1ff1551f080e3b07a0102759e07512420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb6222da7394e1086f92ea559d4642d0f2df179d48839c33ebb6bccf79a3755ab99281bc11ef4f27b82eca08b828a90b98cdd6ce5c36b74fcb21cd6819d8201bd3800000168000000b01b4c0e0dfd0c9693a8336fe0ef655f693ceb64de1be5ffe8ff2dc81d520a26f116420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb60981c05d0866b8f66e41dad67c3a604c7912312c86d0c604ec112a137205f2140f6fda42af48ad802c3d0c84a29e0aab65054267b88283fb9d1ab416bcb203b3000000b002a02731b762c890e7cff0e30772b087c483c18268f387327f71fa968cba6d6c1a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb6213a27f3a3ee8b1d662ea18f15c909c828de76194d97bddfb03752209cb63890272841d94ad07fa72429d33d3c2cb42714d187547f497bd66140dc23e7624a2f00000168000000b01a588ec852ea9ab7dfbcb79ba1015a037450066f2fba7f0d439822a3b76ab3e81e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb6088e41175e44bd1aa5cb22912dd65ae6b076d2bd9aa54529307b8499d7667f0b0e7c5afd0526b1a463c6543f543a05459c69e3f8cc57031fe1850e9d221290aa000000b001aca7ec0d40ccb51f59389db90eab21fbe863137cc80656c3dc551cf21afa6322420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb62046a8adf9cc8f419db7e949c7650462604317aa616c3d03f4a1aca70216c5872634c293a0ae83cb5bb31af7edc8aec14c3628e5931dfafaa5ab36aa4cc2d72600000168000000b019650f82a8c89edc1745ff56529d549dabb4a800438efe3188027d2a1ccb40df26420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb6079ac1d1b422c13edd546a4bdf725580e7db744eae79c44d74e5df203cc70c020d88dbb75b04b5c89b4f9bfa05d5ffdfd3ce8589e02b824425ef692387731da1000000b000b928a6631ed0d956e280586aaaa5bc334d04a4909c857b0846afa3577b875a2a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb61f5329684faa9365d54131047900fefc97a7b93b7540bc28390c072d6777527e2541434df68c87ef933c62b29f64a95b839aca76a6f27a1eea159130b223641d00000168000000b01871903cfea6a3004ecf471104394f37e319499157637d55cc6cd7b0822bcdd62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb606a7428c0a00c56314ddb206910e501b1f4015dfc24e4371b95039a6a22798f90c955c71b0e2b9ecd2d8e3b4b771fa7a0b33271af40001686a59c3a9ecd3aa98000000b03029f7d39a2e752746bc0dc99dc7f8b392e58e7e1e2a75309092ffbdacdc145232420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb61e5faa22a588978a0cca78bf2a9cf996cf0c5acc89153b4c7d7661b3ccd7df75244dc4084c6a8c13cac5aa6d5100a3f5baff6c07bac6f9432e7febb71783f11400000168000000b0177e10f75484a72486588ecbb5d549d21a7deb226b37fc7a10d73236e78c5acd36420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb605b3c3465fdec9874c66f9c142aa4ab556a4b770d622c295fdba942d078825f00ba1dd2c06c0be110a622b6f690df5144297c8ac07d4808caec41e305234378f000000b02f36788df00c794b7e4555844f63f34dca4a300f31fef454d4fd5a44123ca1493a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb61d6c2adcfb669bae4453c079dc38f4310670fc5d9ce9ba70c1e0bc3a32386c6c235a44c2a2489038024ef228029c9e8ff2640d98ce9b786772ea463d7ce47e0b00380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b0168a91b1aa62ab48bde1d6866771446c51e28cb37f0c7b9e55418cbd4cece7c43e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb604c04400b5bccdab83f0417bf446454f8e095901e9f741ba4224eeb36ce8b2e70aae5de65c9ec23541eb732a1aa9efae79fc6a3d1ba8ffb0f32e78b6b794c486000000b02e42f94845ea7d6fb5ce9d3f00ffede801aed1a045d373791967b4ca779d2e4042420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb61c78ab9751449fd27bdd08348dd4eecb3dd59deeb0be3995064b16c09798f9632266c57cf826945c39d839e2b438992a29c8af29e26ff78bb754a0c3e2450b02000000b01597126c0040af6cf56b1e41190d3f0689472e4492e0fac299abe743b24d74bb46420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb603ccc4bb0b9ad1cfbb798936a5e23fe9c56dfa92fdcbc0de868f4939d2493fde09badea0b27cc6597974bae4cc45ea48b1610bce2f7d7ed53798d33d1cf5517d0000021c000000b02d4f7a029bc88193ed57e4f9b29be8823913733159a7f29d5dd20f50dcfdbb374a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb61b852c51a722a3f6b3664fef3f70e965753a3f7fc492b8b94ab57146fcf9865a217346374e0498807161819d65d493c4612d50baf64476affbbefb4a47a597f9000000b014a39326561eb3912cf465fbcaa939a0c0abcfd5a6b579e6de1641ca17ae01b24e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb602d945756178d5f3f302d0f1577e3a83fcd29c2411a04002caf9a3c037a9ccd508c75f5b085aca7db0fe029f7de1e4e2e8c5ad5f4351fdf97c032dc38255de74000000b02c5bfabcf1a685b824e12cb46437e31c707814c26d7c71c1a23c69d7425e482e52420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb61a91ad0bfd00a81aeaef97a9f10ce3ffac9ee110d86737dd8f1fcbcd625a1351207fc6f1a3e29ca4a8eac95817708e5e9891f24c0a18f5d4402955d0ad0624f00000021c000000b013b013e0abfcb7b5647dadb67c45343af8107166ba89f90b22809c507d0e8ea956420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb601e5c62fb756da182a8c18ac091a351e34373db52574bf270f63fe469d0a59cc07d3e0155e38cea1e8874a5a2f7ddf7d202a4ef057267d1dc06d8849e7b66b6b000000b02b687b77478489dc5c6a746f15d3ddb6a7dcb6538150f0e5e6a6c45da7bed5255a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb6199e2dc652deac3f2278df64a2a8de99e40382a1ec3bb701d38a2653c7baa0481f8c47abf9c0a0c8e0741112c90c88f8cff693dd1ded74f88493b0571266b1e7000000b012bc949b01dabbd99c06f5712de12ed52f7512f7ce5e782f66eaf6d6e26f1ba05e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb600f246ea0d34de3c62156066bab62fb86b9bdf4639493e4b53ce58cd026ae6c306e060cfb416d2c620109214e119da17578ef0816afafc4204d7e2d04d16f8620000021c000000b02a74fc319d628e0093f3bc29c76fd850df4157e49525700a2b111ee40d1f621c62420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb618aaae80a8bcb0635a02271f5444d9341b6824330010362617f480da2d1b2d3f1e98c8664f9ea4ed17fd58cd7aa88393075b356e31c1f41cc8fe0add77c73ede000000b011c9155557b8bffdd3903d2bdf7d296f66d9b488e232f753ab55515d47cfa89766420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb6306316174444828a51eeedd7edd382afcb34691fc6d72e00dc1aa8e757cb73bb05ece18a09f4d6ea5799d9cf92b5d4b18ef392127ecf7b6649423d56b2778559000000b029817cebf3409224cb7d03e4790bd2eb16a5f975a8f9ef2e6f7b796a727fef136a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb617b72f3afe9ab487918b6eda05e0d3ce52ccc5c413e4b54a5c5edb60927bba361da54920a57ca9114f86a0882c447e2d3ebfd6ff459673410d686563dd27cbd50000021c000000b010d5960fad96c4220b1984e6911924099e3e5619f6077677efbfabe3ad30358e6e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb62f6f96d19a2286ae897835929f6f7d4a02990ab0daabad252085036dbd2c00b204f962445fd2db0e8f23218a4451cf4bc65833a392a3fa8a8dac97dd17d81250000000b0288dfda6491e964903064b9f2aa7cd854e0a9b06bcce6e52b3e5d3f0d7e07c0a72420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb616c3aff55478b8abc914b694b77cce688a31675527b9346ea0c935e6f7dc472d1cb1c9dafb5aad35870fe842dde078c776247890596af26551d2bfea428858cc000000b00fe216ca0374c84642a2cca142b51ea3d5a2f7ab09dbf59c342a066a1290c28576420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb62e7c178bf0008ad2c1017d4d510b77e439fdac41ee802c4964ef5df4228c8da90405e2feb5b0df32c6ac6944f5edc9e5fdbcd534a67879aed216f2637d389f470000021c000000b0279a7e609efc9a6d3a8f9359dc43c81f856f3c97d0a2ed76f8502e773d4109017a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb615d030afaa56bcd0009dfe4f6918c902c19608e63b8db392e533906d5d3cd4241bbe4a955138b159be992ffd8f7c7361ad891a216d3f7189963d1a70a7e8e5c3000000b00eee97845952cc6a7a2c145bf451193e0d07993c1db074c0789460f077f14f7c7e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb62d88984645de8ef6f88ac50802a7727e71624dd30254ab6da959b87a87ed1aa0031263b90b8ee356fe35b0ffa789c480352176c5ba4cf8d316814ce9e2992c3e000000b026a6ff1af4da9e917218db148ddfc2b9bcd3de28e4776c9b3cba88fda2a195f882420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb614dcb16a0034c0f43827460a1ab4c39cf8faaa774f6232b7299deaf3c29d611b1acacb4fa716b57df62277b841186dfbe4edbbb28113f0addaa774f70d4972ba0000021c000000b00dfb183eaf30d08eb1b55c16a5ed13d8446c3acd3184f3e4bcfebb76dd51dc7386420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb62c9519009bbc931b30140cc2b4436d18a8c6ef6416292a91edc41300ed4da797021ee473616ce77b35bef8ba5925bf1a6c861856ce2177f75aeba77047f9b935000000b025b37fd54ab8a2b5a9a222cf3f7bbd53f4387fb9f84bebbf8124e384080222ef8a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb613e932245612c5186fb08dc4cc50be37305f4c086336b1db6e08457a27fdee1219d74c09fcf4b9a22dabbf72f2b468961c525d4394e86fd21f11cf7d72a9ffb1000000b00d0798f9050ed4b2e93ea3d157890e727bd0dc5e45597309016915fd42b2696a8e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb62ba199baf19a973f679d547d65df67b2e02b90f529fda9b6322e6d8752ae348e012b652db74aeb9f6d4840750ac1b9b4a3eab9e7e1f5f71b9f5601f6ad5a462c0000021c000000b024c0008fa096a6d9e12b6a89f117b7ee2b9d214b0c206ae3c58f3e0a6d62afe692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb612f5b2deabf0c93ca739d57f7decb8d167c3ed99770b30ffb272a0008d5e7b0918e3ccc452d2bdc66535072da450633053b6fed4a8bceef6637c2a03d80a8ca8000000b00c1419b35aecd8d720c7eb8c0925090cb3357def592df22d45d37083a812f66196420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb62aae1a7547789b639f269c38177b624d179032863dd228da7698c80db80ec1850037e5e80d28efc3a4d1882fbc5db44edb4f5b78f5ca763fe3c05c7d12bad323000000b023cc8149f674aafe18b4b244a2b3b2886301c2dc1ff4ea0809f99890d2c33cdd9a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb61202339901cecd60dec31d3a2f88b36b9f288f2a8adfb023f6dcfa86f2bf080017f04d7ea8b0c1ea9cbe4ee855ec5dca8b1ba065bc916e1aa7e6848a3d6b199f00000fa400000168000000b00b209a6db0cadcfb58513346bac103a6ea9a1f806d0271518a3dcb0a0d7383589e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb629ba9b2f9d569f87d6afe3f2c9175ce74ef4d41751a6a7febb0322941d6f4e7c2fa8b5154438941194ab15a0ef7b07463ae7e552835865f56c0cac97681b601b000000b022d902044c52af22503df9ff544fad229a66646d33c9692c4e63f3173823c9d4a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6110eb45357acd185164c64f4e124ae05d68d30bb9eb42f483b47550d581f94f716fcce38fe8ec60ed44796a307885864c28041f6d065ed3eec50df10a2cba69600000168000000b00a2d1b2806a8e11f8fda7b016c5cfe4121fec11180d6f075cea8259072d4104fa6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb628c71be9f334a3ac0e392bad7ab35781865975a8657b2722ff6d7d1a82cfdb732eb535cf9a169835cc345d5ba11701e0724c86e3972ce519b077071dcd7bed12000000b021e582bea230b34687c741ba05eba7bcd1cb05fe479de85092ce4d9d9d8456cbaa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6101b350dad8ad5a94dd5acaf92c0a8a00df1d24cb288ae6c7fb1af93bd8021ee16094ef3546cca330bd0de5db92452fef9e4e387e43a6c6330bb3997082c338d00000168000000b009399be25c86e543c763c2bc1df8f8db596362a294ab6f9a13128016d8349d46ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb627d39ca44912a7d045c273682c4f521bbdbe1739794fa64743d7d7a0e830686a2dc1b689eff49c5a03bda51652b2fc7aa9b12874ab01643df4e161a432dc7a09000000b020f20378f80eb76abf508974b787a257092fa78f5b726774d738a82402e4e3c2b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb60f27b5c80368d9cd855ef46a445ca33a455673ddc65d2d90c41c0a1a22e0aee51515cfadaa4ace57435a26186ac04d9931498518f80eeb877525941d6d8cc08400000168000000b008461c9cb264e967feed0a76cf94f37590c80433a87feebe577cda9d3d952a3db6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb626e01d5e9ef0abf47d4bbb22ddeb4cb5f522b8ca8d24256b884232274d90f5612cce374445d2a07e3b46ecd1044ef714e115ca05bed5e362394bbc2a983d0700000000b01ffe84334decbb8ef6d9d12f69239cf1409449206f46e6991ba302aa684570b9ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb60e3436825946ddf1bce83c24f5f89dd47cbb156eda31acb5088664a088413bdc142250680028d27b7ae36dd31c5c483368ae26aa0be36aabb98feea3d2ed4d7b00000168000000b007529d570842ed8c367652318130ee0fc82ca5c4bc546de29be73523a2f5b734be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb625ec9e18f4ceb018b4d502dd8f8747502c875a5ba0f8a48fccac8cadb2f182582bdab7fe9bb0a4a272d0348bb5eaf1af187a6b96d2aa62867db616b0fd9d93f7000000b01f0b04eda3cabfb32e6318ea1abf978b77f8eab1831b65bd600d5d30cda5fdb0c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb60d40b73caf24e215f47183dfa794986eb41fb6ffee062bd94cf0bf26eda1c8d3132ed1225606d69fb26cb58dcdf842cda012c83b1fb7e9cffdfa492a384dda7200000168000000b0065f1e115e20f1b06dff99ec32cce8a9ff914755d028ed06e0518faa0856442bc6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb624f91ed34aacb43cec5e4a98412341ea63ebfbecb4cd23b41116e73418520f4f2ae738b8f18ea8c6aa597c466786ec494fdf0d27e67ee1aac220713762fe20ee000000b01e1785a7f9a8c3d765ec60a4cc5b9225af5d8c4296efe4e1a477b7b733068aa7ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb60c4d37f70502e63a2bfacb9a59309308eb84589101daaafd915b19ad530255ca123b51dcabe4dac3e9f5fd487f943d67d77769cc338c68f44264a3b09dae676900000168000000b0056b9ecbb3fef5d4a588e1a6e468e34436f5e8e6e3fd6c2b24bbea306db6d122ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb624059f8da08ab86123e79252f2bf3c849b509d7dc8a1a2d8558141ba7db29c4629f3b973476caceae1e2c4011922e6e38743aeb8fa5360cf068acbbdc85eade5000000b01d2406624f86c7fb9d75a85f7df78cbfe6c22dd3aac46405e8e2123d9867179ed2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb60b59b8b15ae0ea5e638413550acc8da322e8fa2215af2a21d5c57433b862e2c11147d29701c2dee8217f4503313038020edc0b5d4760e81886cefe37030ef46000000168000000b004781f8609dcf9f8dd1229619604ddde6e5a8a77f7d1eb4f692644b6d3175e19d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb623122047f668bc855b70da0da45b371ed2b53f0edc7621fc99eb9c40e313293d29003a2d9d4ab10f196c0bbbcabee17dbea8504a0e27dff34af526442dbf3adc000000b01c30871ca564cc1fd4fef01a2f93875a1e26cf64be98e32a2d4c6cc3fdc7a495da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb60a66396bb0beee829b0d5b0fbc68883d5a4d9bb32983a9461a2fceba1dc36fb81054535157a0e30c59088cbde2cc329c4640acee5b35673ccb3958bd686f815700000168000000b00384a0405fbafe1d149b711c47a0d878a5bf2c090ba66a73ad909f3d3877eb10de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6221ea1024c46c0a992fa21c855f731b90a19e09ff04aa120de55f6c74873b634280cbae7f328b53350f553767c5adc17f60cf1db21fc5f178f5f80ca931fc7d3000000b01b3d07d6fb42d0440c8837d4e12f81f4558b70f5d26d624e71b6c74a6328318ce2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb60972ba26069cf2a6d296a2ca6e0482d791b23d443d58286a5e9a29408323fcaf0f60d40bad7ee7309091d47894682d367da54e7f6f09e6610fa3b343cdd00e4e00000168000000b0029120fab59902414c24b8d6f93cd312dd23cd9a1f7ae997f1faf9c39dd87807e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6212b21bca224c4cdca83698307932c53417e8231041f204522c0514dadd4432b27193ba24906b957887e9b312df6d6b22d71936c35d0de3bd3c9db50f88054ca000000b01a4988915120d46844117f8f92cb7c8e8cf01286e641e172b62121d0c888be83ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6087f3ae05c7af6cb0a1fea851fa07d71c916ded5512ca78ea30483c6e88489a60e6d54c6035ceb54c81b1c33460427d0b509f01082de6585540e0dca33309b4500000168000000b0019da1b50b77066583ae0091aad8cdad14886f2b334f68bc3665544a033904feee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb62037a276f802c8f2020cb13db92f26ed78e323c217f39f69672aabd41334d0222625bc5c9ee4bd7bc007e2ebdf92d14c64d634fd49a55d60183435d75de0e1c1000000b01956094ba6fed88c7b9ac74a44677728c454b417fa166096fa8b7c572de94b7af2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6078bbb9ab258faef41a9323fd13c780c007b8066650126b2e76ede4d4de5169d0d79d580593aef78ffa463edf7a0226aec6e91a196b2e4a9987868509891283c003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b000aa226f61550a89bb37484c5c74c8474bed10bc4723e7e07acfaed0689991f5f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb61f4423314de0cd163995f8f86acb2187b047c5532bc81e8dab95065a78955d1925323d16f4c2c19ff7912aa6912ecbe69c3ad68e5d79dc845c9e905dc3416eb8000000b018628a05fcdcdcb0b3240f04f60371c2fbb955a90deadfbb3ef5d6dd9349d871fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb606983c550836ff13793279fa82d872a637e021f778d5a5d72bd938d3b345a3940c86563aaf18f39d372daba8a93c1d0523d33332aa8763cddce2c2d6fdf1b533000000b0301af19c9864aed7ab10d5bd8f921b3eab859a95d4b1d796031bfeeabdfa1eedfe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb61e50a3eba3bed13a711f40b31c671c21e7ac66e43f9c9db1efff60e0ddf5ea10243ebdd14aa0c5c42f1a726142cac680d39f781f714e5ba8a108eae428a1fbaf0000021c000000b017d694d622c36bc899c87f4ec7d726dec97d7ae3dec6ff2ab39c929a6dd3729902430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb6060c47252e1d8e2b5fd6ea4454ac27c205a4473249b1c546a07ff4908dcf3dbc0bfa610ad4ff82b51dd21bf27b0fd220f197586d7b63833d51897e93d87b4f5b000000b02f8efc6cbe4b3def91b546076165d05a7949bfd0a58df70577c2baa79883b91506430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb61dc4aebbc9a5605257c3b0fcee3ad13db5708c1f1078bd2164a61c9db87f843823b2c8a1708754dc15bee2ab149e7b9ca1639d5a422a7b1815afa6a1032b95d7000000b016e3159078a16fecd151c7097973217900e21c74f29b7e4ef806ed20d333ff900a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60518c7df83fb924f976031ff0648225c3d08e8c35d86446ae4ea4f16f32fcab30b06e1c52add86d9555b63ad2cabccbb28fbf9fe8f38026195f3d91a3ddbdc520000021c000000b02e9b7d2714294213c93e8dc21301caf4b0ae6161b9627629bc2d152dfde4460c0e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb61cd12f761f8364768f4cf8b79fd6cbd7ecd52db0244d3c45a91077241de0112f22bf495bc66559004d482a65c63a7636d8c83eeb55fefa3c5a1a0127688c22ce000000b015ef964ace7f741108db0ec42b0f1c133846be06066ffd733c7147a738948c8712430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb604254899d9d99673cee979b9b7e41cf6746d8a54715ac38f2954a99d589057aa0a13627f80bb8afd8ce4ab67de47c75560609b8fa30c8185da5e33a0a33c6949000000b02da7fde16a07463800c7d57cc49dc58ee81302f2cd36f54e00976fb46344d30316430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb61bddb0307561689ac6d640725172c6722439cf413821bb69ed7ad1aa83409e2621cbca161c435d2484d1722077d670d1102ce07c69d379609e845badcdecafc50000021c000000b014fc1705245d78354064567edcab16ad6fab5f971a447c9780dba22d9df5197e1a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb60331c9542fb79a980672c17469801790abd22be5852f42b36dbf0423bdf0e4a1091fe339d6998f21c46df3228fe3c1ef97c53d20b6e100aa1ec88e27089cf640000000b02cb47e9bbfe54a5c38511d377639c0291f77a483e10b74724501ca3ac8a55ffa1e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61aea30eacb3f6cbefe5f882d030ec10c5b9e70d24bf63a8e31e52c30e8a12b1d20d84ad072216148bc5ab9db29726b6b4791820d7da7f884e2eeb634334d3cbc000000b0140897bf7a3b7c5977ed9e398e471147a71001282e18fbbbc545fcb40355a67522430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb6023e4a0e85959ebc3dfc092f1b1c122ae336cd769903c1d7b2295eaa23517198082c63f42c779345fbf73add417fbc89cf29deb1cab57fce6332e8ad6dfd83370000021c000000b02bc0ff5615c34e806fda64f227d5bac356dc4614f4dff396896c24c12e05ecf126430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb619f6b1a5211d70e335e8cfe7b4aabba6930312635fcab9b2764f86b74e01b8141fe4cb8ac7ff656cf3e40195db0e66057ef6239e917c77a9275910ba98adc9b3000000b013151879d019807daf76e5f43fe30be1de74a2b941ed7ae009b0573a68b6336c2a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb6014acac8db73a2e0758550e9ccb80cc51a9b6f07acd840fbf693b93088b1fe8f0738e4ae8255976a33808297f31bb724068e8042de89fef2a79d4333d35e102e000000b02acd80106ba152a4a763acacd971b55d8e40e7a608b472bacdd67f47936679e82e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb61903325f76fb75076d7217a26646b640ca67b3f4739f38d6bab9e13db362450b1ef14c451ddd69912b6d49508caa609fb65ac52fa550f6cd6bc36b40fe0e56aa0000021c000000b01221993425f784a1e7002daef17f067c15d9444a55c1fa044e1ab1c0ce16c06332430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb600574b833151a704ad0e98a47e54075f52001098c0acc0203afe13b6ee128b8606456568d8339b8e6b09ca52a4b7b1be3df321d3f25e7e16ec079dba38be9d25000000b029da00cac17f56c8deecf4678b0daff7c5a589371c88f1df1240d9cdf8c706df36430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb6180fb319ccd9792ba4fb5f5d17e2b0db01cc55858773b7faff243bc418c2d2021dfdccff73bb6db562f6910b3e465b39edbf66c0b92575f1b02dc5c7636ee3a1000000b0112e19ee7bd588c61e897569a31b01164d3de5db6996792892850c4733774d5a3a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb62fc81ab068614b529ce82615b1715a56b1989a724e3aafd5c34a63d14373187e0551e6232e119fb2a293120d5653ac587557c3650632fd3b3071f8409e1f2a1c0000021c000000b028e68185175d5aed16763c223ca9aa91fd0a2ac8305d710356ab34545e2793d63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb6171c33d422b77d4fdc84a717c97eab753930f7169b48371f438e964a7e235ef91d0a4db9c99971d99a7fd8c5efe255d425240851ccf9f515f498204dc8cf7098000000b0103a9aa8d1b38cea5612bd2454b6fbb084a2876c7d6af84cd6ef66cd98d7da5142430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb62ed49b6abe3f4f76d4716dd0630d54f0e8fd3c03620f2efa07b4be57a8d3a575045e66dd83efa3d6da1c59c807efa6f2acbc64f61a077c5f74dc52c7037fb713000000b027f3023f6d3b5f114dff83dcee45a52c346ecc594431f0279b158edac38820cd46430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb61628b48e78958174140deed27b1aa60f709598a7af1cb64387f8f0d0e383ebf01c16ce741f7775fdd2092080a17e506e5c88a9e2e0ce743a39027ad42e2ffd8f0000021c000000b00f471b632791910e8d9c04df0652f64abc0728fd913f77711b59c153fe3867484a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb62de11c25141d539b0bfab58b14a94f8b2061dd9475e3ae1e4c1f18de0e34326c036ae797d9cda7fb11a5a182b98ba18ce42106872ddbfb83b946ad4d68e0440a000000b026ff82f9c31963358588cb979fe19fc66bd36dea58066f4bdf7fe96128e8adc44e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb615353548ce7385984b97368d2cb6a0a9a7fa3a38c2f13567cc634b5748e478e71b234f2e75557a220992683b531a4b0893ed4b73f4a2f35e7d6cd55a93908a86000000b00e539c1d7d6f9532c5254c99b7eef0e4f36bca8ea513f6955fc41bda6398f43f52430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb62ced9cdf69fb57bf4383fd45c6454a2557c67f2589b82d42908973647394bf63027768522fabac1f492ee93d6b279c271b85a81841b07aa7fdb107d3ce40d10100000fa400000168000000b0260c03b418f76759bd121352517d9a60a3380f7b6bdaee7023ea43e78e493abb56430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb61441b603245189bc83207e47de529b43df5edbc9d6c5b48c10cda5ddae4505de1a2fcfe8cb337e46411baff604b645a2cb51ed0508777282c1d72fe0f8f1177d000000b00d601cd7d34d9956fcae9454698aeb7f2ad06c1fb8e875b9a42e7660c8f981365a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb62bfa1d99bfd95be37b0d450077e144bf8f2b20b69d8cac66d4f3cdead8f54c5a0183e90c8589b04380b830f81cc396c152ea49a95584f9cc421b625a33a15df800000168000000b02518846e6ed56b7df49b5b0d031994fada9cb10c7faf6d9468549e6df3a9c7b25e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb6134e36bd7a2f8de0baa9c6028fee95de16c37d5aea9a33b05538006413a592d5193c50a32111826a78a4f7b0b652403d02b68e961c4bf1a706418a675e51a474000000b00c6c9d92292b9d7b3437dc0f1b26e61962350db0ccbcf4dde898d0e72e5a0e2d62430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb62b069e5415b76007b2968cbb297d3f59c68fc247b1612b8b195e28713e55d951009069c6db67b467b84178b2ce5f915b8a4eeb3a695978f08685bce09901eaef00000168000000b024250528c4b36fa22c24a2c7b4b58f951201529d9383ecb8acbef8f4590a54a966430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb6125ab777d00d9204f2330dbd418a90784e281eebfe6eb2d499a25aea79061fcc1848d15d76ef868eb02e3f6b67ee3ad73a1b3027302070cb4aabe4edc3b2316b000000b00b791e4c7f09a19f6bc123c9ccc2e0b39999af41e09174022d032b6d93ba9b246a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb62a131f0e6b95642bea1fd475db1939f3fdf463d8c535aaaf5dc882f7a3b66648300138f4127758b5a81b0624017ce452e9e77513f6e768a60ed20cfaee6277e700000168000000b0233185e31a9173c663adea8266518a2f4965f42ea7586bdcf129537abe6ae1a06e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb61167383225eb962929bc5577f3268b12858cc07d124331f8de0cb570de66acc317555217cccd8ab2e7b78726198a3571717fd1b843f4efef8f163f742912be62000000b00a859f06d4e7a5c3a34a6b847e5edb4dd0fe50d2f465f326716d85f3f91b281b72430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb6291f9fc8c173685021a91c308cb5348e35590569d90a29d3a232dd7e0916f33f2f0db9ae68555cd9dfa44ddeb318deed214c16a50abbe7ca533c678153c304de00000168000000b0223e069d706f77ea9b37323d17ed84c980ca95bfbb2ceb013593ae0123cb6e9776430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb61073b8ec7bc99a4d61459d32a4c285acbcf1620e2617b11d22770ff743c739ba1661d2d222ab8ed71f40cee0cb26300ba8e4734957c96f13d38099fa8e734b59000000b009921fc12ac5a9e7dad3b33f2ffad5e80862f264083a724ab5d7e07a5e7bb5127a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb6282c208317516c74593263eb3e512f286cbda6faecdea8f7e69d38046e7780362e1a3a68be3360fe172d959964b4d98758b0b8361e9066ee97a6c207b92391d500000168000000b0214a8757c64d7c0ed2c079f7c9897f63b82f3750cf016a2579fe0887892bfb8e7e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb60f8039a6d1a79e7198cee4ed565e8046f456039f39ec304166e16a7da927c6b1156e538c788992fb56ca169b7cc22aa5e04914da6b9dee3817eaf480f3d3d850000000b0089ea07b80a3ae0c125cfaf9e196d0823fc793f51c0ef16efa423b00c3dc420982430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb62738a13d6d2f709890bbaba5efed29c2a422488c00b3281c2b07928ad3d80d2d2d26bb23141165224eb6dd541650d421901559c73264e612dc111c8e1e841ecc00000168000000b0205708121c2b80330a49c1b27b2579fdef93d8e1e2d5e949be68630dee8c888586430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb60e8cba612785a295d0582ca807fa7ae12bbaa5304dc0af65ab4bc5040e8853a8147ad446ce67971f8e535e562e5e254017adb66b7f726d5c5c554f0759346547000000b007ab2135d681b23049e642b49332cb1c772c35862fe370933eac9587293ccf008a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb6264521f7c30d74bcc844f360a189245cdb86ea1d1487a7406f71ed1139389a242c333bdd69ef69468640250ec7eccebbc779fb5846396537207b771483e4abc300000168000000b01f6388cc7209845741d3096d2cc1749826f87a72f6aa686e02d2bd9453ed157c8e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb60d993b1b7d63a6ba07e17462b996757b631f46c161952e89efb61f8a73e8e09f1387550124459b43c5dca610dffa1fda4f1257fc9346ec80a0bfa98dbe94f23e000000b006b7a1f02c5fb654816f8a6f44cec5b6ae90d71743b7efb78316f00d8e9d5bf792430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb62551a2b218eb78e0ffce3b1b53251ef712eb8bae285c2664b3dc47979e99271b2b3fbc97bfcd6d6abdc96cc97988c955fede9ce95a0de45b64e5d19ae94538ba00000168000000b01e700986c7e7887b795c5127de5d6f325e5d1c040a7ee792473d181ab94da27396430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb60ca5bbd5d341aade3f6abc1d6b3270159a83e8527569adae34207a10d9496d961293d5bb7a239f67fd65edcb91961a748676f98da71b6ba4e52a041423f57f35000000b005c422aa823dba78b8f8d229f66ac050e5f578a8578c6edbc7814a93f3fde8ee9a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb6245e236c6ec97d05375782d604c119914a502d3f3c30a588f846a21e03f9b4122a4c3d5215ab718ef552b4842b24c3f036433e7a6de2637fa9502c214ea5c5b100000168000000b01d7c8a411dc58c9fb0e598e28ff969cc95c1bd951e5366b68ba772a11eae2f6a9e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb60bb23c90291faf0276f403d81cce6aafd1e889e3893e2cd2788ad4973ea9fa8d11a05675d001a38c34ef35864332150ebddb9b1ebaefeac929945e9a89560c2c000000b004d0a364d81bbe9cf08219e4a806baeb1d5a1a396b60ee000beba51a595e75e5a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6236aa426c4a781296ee0ca90b65d142b81b4ced0500524ad3cb0fca4695a41092958be0c6b8975b32cdbfc3edcc0be8a6da7e00b81b6e2a3edba86a7b40652a800000168000000b01c890afb73a390c3e86ee09d41956466cd265f263227e5dad011cd27840ebc61a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb60abebd4a7efdb326ae7d4b92ce6a654a094d2b749d12abf6bcf52f1da40a878410acd73025dfa7b06c787d40f4ce0fa8f5403cafcec469ed6dfeb920eeb69923000000b003dd241f2df9c2c1280b619f59a2b58554bebbca7f356d245055ffa0bebf02dcaa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6227724e11a85854da66a124b67f90ec5b919706163d9a3d1811b572acebace0028653ec6c16779d7646543f98e5cb924a50c819c958b61c83224e12e1966df9f00380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b01b958bb5c98194e81ff82857f3315f01048b00b745fc64ff147c27ade96f4958ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb609cb3e04d4dbb74ae606934d80065fe440b1cd05b0e72b1b015f89a4096b147b0fb957ea7bbdabd4a401c4fba66a0a432ca4de40e298e911b26913a75417261a000000b002e9a4d983d7c6e55f94a95a0b3eb01f8c235d5b9309ec4894c05a27241f8fd3b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb62183a59b70638971ddf35a061995095ff07e11f277ae22f5c585b1b1341b5af72771bf8117457dfb9bee8bb43ff8b3bedc71232da95fe0ec768f3bb47ec76c96000000b01aa20c701f5f990c57817012a4cd599b3befa24859d0e42358e682344ecfd64fb6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb608d7bebf2ab9bb6f1d8fdb0831a25a7e78166e96c4bbaa3f45c9e42a6ecba1720ec5d8a4d19baff8db8b0cb6580604dd64097fd1f66d6835f6d36e2db977b3110000021c000000b001f62593d9b5cb09971df114bcdaaab9c387feeca6de6b6cd92ab4ad89801ccaba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb620902655c6418d96157ca1c0cb3103fa27e2b3838b82a21a09f00c37997be7ee267e403b6d23821fd377d36ef194ae5913d5c4bebd346010baf9963ae427f98d000000b019ae8d2a753d9d308f0ab7cd56695435735443d96da563479d50dcbab4306346be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb607e43f798097bf93551922c2e33e5518af7b1027d89029638a343eb0d42c2e690dd2595f2779b41d1314547109a1ff779b6e21630a41e75a3b3dc8b41ed84008000000b00102a64e2f93cf2dcea738cf6e76a553faeca07dbab2ea911d950f33eee0a9c1c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb61f9ca7101c1f91ba4d05e97b7cccfe945f4755149f57213e4e5a66bdfedc74e5258ac0f5c30186440b011b29a330a8f34b3a664fd108df34ff63f0c1498886840000021c000000b018bb0de4cb1ba154c693ff8808054ecfaab8e56a8179e26be1bb37411990f03dc6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb606f0c033d675c3b78ca26a7d94da4fb2e6dfb1b8ec64a887ce9e9937398cbb600cdeda197d57b8414a9d9c2bbb3dfa11d2d2c2f41e16667e7fa8233a8438ccff000000b0000f27088571d3520630808a20129fee3251420ece8769b561ff69ba544136b8ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb61ea927ca71fd95de848f31362e68f92e96abf6a5b32ba06292c4c144643d01dc249741b018df8a68428a62e454cca38d829f07e0e4dd5e5943ce4b47aee9137b000000b017c78e9f20f9a578fe1d4742b9a14969e21d86fb954e6190262591c77ef17d34ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb605fd40ee2c53c7dbc42bb23846764a4d1e44534a003927ac1308f3bd9eed48570beb5ad3d335bc658226e3e66cd9f4ac0a37648531eae5a2c4127dc0e99959f60000021c000000b02f7ff635bc81779ff60a0dfb532ff2e591e9cbe85c15596aea4bb9d4a9a1c3b0d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb61db5a884c7db9a02bc1878f0e004f3c8ce109836c7001f86d72f1bcac99d8ed323a3c26a6ebd8e8c7a13aa9f06689e27ba03a971f8b1dd7d8838a5ce1449a072000000b016d40f5976d7a99d35a68efd6b3d44041982288ca922e0b46a8fec4de4520a2bd6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb60509c1a88231cbfffbb4f9f2f81244e755a8f4db140da6d057734e44044dd54e0af7db8e2913c089b9b02ba11e75ef46419c061645bf64c7087cd8474ef9e6ed000000b02e8c76f0125f7bc42d9355b604cbed7fc94e6d796fe9d88f2eb6145b0f0250a7da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb61cc2293f1db99e26f3a1c0ab91a0ee63057539c7dad49eab1b9976512efe1bca22b04324c49b92b0b19cf259b80498c1f1684b030c865ca1cca3005479aa2d690000021c000000b015e09013ccb5adc16d2fd6b81cd93e9e50e6ca1dbcf75fd8aefa46d449b29722de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb604164262d80fd024333e41ada9ae3f818d0d966c27e225f49bdda8ca69ae62450a045c487ef1c4adf139735bd011e9e07900a7a75993e3eb4ce732cdb45a73e4000000b02d98f7aa683d7fe8651c9d70b667e81a00b30f0a83be57b373206ee17462dd9ee2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb61bcea9f97397a24b2b2b0866433ce8fd3cd9db58eea91dcf6003d0d7945ea8c121bcc3df1a7996d4e9263a1469a0935c28ccec94205adbc6110d5adadf0aba60000000b014ed10ce2293b1e5a4b91e72ce753938884b6baed0cbdefcf364a15aaf132419e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb60322c31d2dedd4486ac789685b4a3a1bc47237fd3bb6a518e0480350cf0eef3c0910dd02d4cfc8d228c2bb1681ade47ab06549386d68630f91518d5419bb00db0000021c000000b02ca57864be1b840c9ca5e52b6803e2b43817b09b9792d6d7b78ac967d9c36a95ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb61adb2ab3c975a66f62b45020f4d8e397743e7cea027d9cf3a46e2b5df9bf35b820c9449970579af920af81cf1b3c8df660318e25342f5aea5577b561446b4757000000b013f991887871b609dc42662d801133d2bfb00d3fe4a05e2137cefbe11473b110ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6022f43d783cbd86ca250d1230ce634b5fbd6d98e4f8b243d24b25dd7346f7c33081d5dbd2aadccf6604c02d13349df14e7c9eac9813ce233d5bbe7da7f1b8dd2000000b02bb1f91f13f98830d42f2ce6199fdd4e6f7c522cab6755fbfbf523ee3f23f78cf2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb619e7ab6e1f53aa939a3d97dba674de31aba31e7b16521c17e8d885e45f1fc2af1fd5c553c6359f1d5838c989ccd8889097962fb64803da0e99e20fe7a9cbd44e0000021c000000b013061242ce4fba2e13cbade831ad2e6cf714aed0f874dd457c39566779d43e07f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6013bc491d9a9dc90d9da18ddbe822f50333b7b1f635fa361691cb85d99d0092a0729de77808bd11a97d54a8be4e5d9af1f2e8c5a951161581a264260e47c1ac9000000b02abe79d969d78c550bb874a0cb3bd7e8a6e0f3bdbf3bd520405f7e74a4848483fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb618f42c287531aeb7d1c6df965810d8cbe307c00c2a269b3c2d42e06ac4804fa61ee2460e1c13a3418fc211447e74832acefad1475bd85932de4c6a6e0f2c6145000000b0121292fd242dbe524b54f5a2e34929072e7950620c495c69c0a3b0eddf34cafefe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb60048454c2f87e0b511636098701e29ea6aa01cb077342285ad8712e3ff30962106365f31d669d53ecf5e92469681d44956932deba8e5e07c5e909ce749dca7c00000021c000000b02a3284a98fbe1b6cf25ce4ea9d0f8d0474a518f89017f48fb5063a317f0e1eab02440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb6186836f89b183dcfb86b4fe029e48de7b0cbe546fb02baaba1e99c279f09e9ce1e5650de41fa32597666818e504838469cbef6822cb478a252f3262ae9b5fb6d000000b011869dcd4a144d6a31f965ecb51cde22fc3d759cdd257bd9354a6caab9be652606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb630209e8f36a00ff6b0581698c373376360982a33c1c9b286660fc434c9ba304a05aa6a01fc506456b6030290685589652457532679c1ffebd33758a4246641e8000000b0293f0563e59c1f9129e62ca54eab879eac09ba89a3ec73b3f97094b7e46eaba20a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb61774b7b2f0f641f3eff4979adb808881e83086d80ed739cfe653f6ae046a76c51d62d19897d8367dadefc94901e432e0d42398134088f7c6975d80b14f16886400000fa400000168000000b010931e879ff2518e6982ada766b8d8bd33a2172df0f9fafd79b4c7311f1ef21d0e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb62f2d1f498c7e141ae7e15e53750f31fd97fccbc4d59e31aaaa7a1ebb2f1abd4104b6eabc522e687aed8c4a4b19f183ff5bbbf4b78d967f1017a1b32a89c6cedf000000b0284b861e3b7a23b5616f746000478238e36e5c1ab7c0f2d83ddaef3e49cf389912440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb61681386d46d44618277ddf558d1c831c1f95286922abb8f42abe513469cb03bc1c6f5252edb63aa1e5791103b3802d7b0b8839a4545d76eadbc7db37b477155b00000168000000b00f9f9f41f5d055b2a10bf5621854d3576b06b8bf04ce7a21be1f21b7847f7f1416440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb62e39a003e25c183f1f6aa60e26ab2c97cf616d55e972b0ceeee47941947b4a3803c36b76a80c6c9f25159205cb8d7e9993209648a16afe345c0c0db0ef275bd6000000b0275806d8915827d998f8bc1ab1e37cd31ad2fdabcb9571fc824549c4af2fc5901a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb6158db9279cb24a3c5f0727103eb87db656f9c9fa368038186f28abbacf2b90b31b7bd30d43943ec61d0258be651c281542ecdb356831f60f203235be19d7a25200000168000000b00eac1ffc4bae59d6d8953d1cc9f0cdf1a26b5a5018a2f94602897c3de9e00c0b1e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb62d4620be383a1c6356f3edc8d847273206c60ee6fd472ff3334ed3c7f9dbd72f02cfec30fdea70c35c9ed9c07d297933ca8537d9b53f7d58a07668375487e8cd000000b026648792e7362bfdd08203d5637f776d52379f3cdf69f120c6afa44b1490528722440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb6149a39e1f2904e6096906ecaf05478508e5e6b8b4a54b73cb3930641348c1daa1a8853c7997242ea548ba07916b822af7a517cc67c067533649c90447f382f4900000168000000b00db8a0b6a18c5dfb101e84d77b8cc88bd9cffbe12c77786a46f3d6c44f40990226440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb62c52a1788e1820878e7d358389e321cc3e2ab078111baf1777b92e4e5f3c642601dc6ceb53c874e79428217b2ec573ce01e9d96ac913fc7ce4e0c2bdb9e875c4000000b02571084d3d143022080b4b90151b7207899c40cdf33e70450b19fed179f0df7e2a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb613a6ba9c486e5284ce19b685a1f072eac5c30d1c5e293660f7fd60c799ecaaa11994d481ef50470e8c14e833c8541d49b1b61e578fdaf457a906eacae498bc4000000168000000b00cc52170f76a621f47a7cc922d28c32611349d72404bf78e8b5e314ab4a125f92e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62b5f2232e3f624abc6067d3e3b7f1c66758f520924f02e3bbc2388d4c49cf11d00e8eda5a9a6790bcbb16935e0616e68394e7afbdce87ba1294b1d441f4902bb000000b0247d890792f234463f94934ac6b76ca1c100e25f0712ef694f845957df516c7532440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb612b33b569e4c56a905a2fe40538c6d84fd27aead71fdb5853c67bb4dff4d379818a1553c452e4b32c39e2fee79f017e3e91abfe8a3af737bed71455149f9493700000168000000b00bd1a22b4d4866437f31144cdec4bdc048993f03542076b2cfc88bd11a01b2f036440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb62a6ba2ed39d428cffd8fc4f8ed1b1700acf3f39a38c4ad60008de35b29fd7e143059bcd2e0b61d59bb8af6a7137ec15f98e704d56a766b56b1976d5e74a98fb3000000b0238a09c1e8d0386a771ddb057853673bf86583f01ae76e8d93eeb3de44b1f96c3a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb611bfbc10f42a5acd3d2c45fb0528681f348c503e85d234a980d215d464adc48f17add5f69b0c4f56fb2777a92b8c127e207f6179b783f2a031db9fd7af59d62e00000168000000b00ade22e5a3266a67b6ba5c079060b85a7ffde09467f4f5d71432e6577f623fe73e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb6297823a78fb22cf435190cb39eb7119ae458952b4c992c8444f83de18f5e0b0b2f663d8d3694217df3143e61c51abbf9d04ba6667e4aea7af601c7e4da0a1caa000000b022968a7c3eae3c8eaea722c029ef61d62fca25812ebbedb1d8590e64aa12866342440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb610cc3ccb4a085ef174b58db5b6c462b96bf0f1cf99a6b3cdc53c705aca0e518616ba56b0f0ea537b32b0bf63dd280d1857e4030acb5871c47645fa5e14ba632500000168000000b009eaa39ff9046e8bee43a3c241fcb2f4b76282257bc974fb589d40dde4c2ccde46440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb62884a461e59031186ca2546e50530c351bbd36bc606daba889629867f4be98022e72be478c7225a22a9d861c76b6b69407b047f7921f699f3a6c226b3f6aa9a1000000b021a30b36948c40b2e6306a7adb8b5c70672ec71242906cd61cc368eb0f73135a4a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb60fd8bd859fe66315ac3ed57068605d53a3559360ad7b32f209a6cae12f6ede7d15c6d76b46c8579f6a3a071e8ec407b28f48a49bdf2cf0e8bab054e47a1af01c00000168000000b008f7245a4ee272b025cceb7cf398ad8eeec723b68f9df41f9d079b644a2359d54e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb62791251c3b6e353ca42b9c2901ef06cf5321d84d74422acccdccf2ee5a1f24f92d7f3f01e25029c66226cdd72852b12e3f14e988a5f3e8c37ed67cf1a4cb3698000000b020af8bf0ea6a44d71db9b2358d27570a9e9368a35664ebfa612dc37174d3a05152440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb60ee53e3ff5c46739e3c81d2b19fc57eddaba34f1c14fb2164e11256794cf6b7414d358259ca65bc3a1c34ed94060024cc6ad462cf301700cff1aaf6adf7b7d1300000168000000b00803a514a4c076d45d563337a534a829262bc547a3727343e171f5eaaf83e6cc56440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb6269da5d6914c3960dbb4e3e3b38b01698a8679de8816a9f112374d74bf7fb1f02c8bbfbc382e2dea99b01591d9eeabc876798b19b9c867e7c340d7780a2bc38f000000b01fbc0cab404848fb5542f9f03ec351a4d5f80a346a396b1ea5981df7da342d485a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb60df1befa4ba26b5e1b5164e5cb985288121ed682d524313a927b7fedfa2ff86b13dfd8dff2845fe7d94c9693f1fbfce6fe11e7be06d5ef31438509f144dc0a0a00000168000000b0071025cefa9e7af894df7af256d0a2c35d9066d8b746f26825dc507114e473c35e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb625aa2690e72a3d85133e2b9e6526fc03c1eb1b6f9beb291556a1a7fb24e03ee72b9840768e0c320ed1395d4c8b8aa662adde2caacd9ce70c07ab31fe6f8c5086000000b01ec88d6596264d1f8ccc41aaf05f4c3f0d5cabc57e0dea42ea02787e3f94ba3f62440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb60cfe3fb4a1806f8252daaca07d344d2249837813e8f8b05ed6e5da745f90856212ec599a4862640c10d5de4ea397f7813576894f1aaa6e5587ef6477aa3c9701", - "txsEffectsHash": "0xbe1ba269c87d75910b743b4192380a38882351d7acb5b6c0fda0c07622480d3f", + "archive": "0x13d7261dd59660d1893de9ca805d5f10670e59d14539b3b5f21888cd047c95b4", + "body": "0x0000000400380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b02407635d98432f42812965e92968d68aafcb34ceafc107bd2c035e90c11c9a061557cd82d076152134014fbbcc418b256a6248bea1499e9f81fa19a78f133209c876f94e2e9cc4cc3b2ea3f6910f7707c29caca7414dfc6f65f94623a1cae72fa06555c695a5922d5f54f073e514af0509e7ab8fa0f9f94570e7ea7403d3bebd25e4cefe998de75a7356a8e76d5791e719e6be1db1aa23beb14fae5049716e1992767754d79ecd5d02f38314b78bf2a2000000b00bfcbdb9d2441d67367a61f13ea52fe937fa48bdc36dc1e5b3a5168a8c87d35e0a9c673b947e6fdec302c2b865c122230d34ae65e58e93a169401f187840f872d866f54ac29f51c943844763598792dd508e600a26fbca3e9d4bb6f0ed968650a9f39454c4274503c108bc91e75745e624d449b332881dae8cd865e15adb7b2db723139e68604b157ddc112a55719e400bcf29e0b47b4823fb1bcd1815907dfba915970945bdd11171b9660f6ce8850d000000b0189f6107cee1019e518a9ad786c8db36307b9a839b123b5a019d9551a3c62f7537fcf7b0717ec89a26937152acd398a8114b13c32908ac54812a5bd25996a3f2170fe03496aaef8f37345ed6a825f930129dea59ad16e1f6f19b5c1196c5a5937d5acc53b37736de48a1d0038f859c7815f5416453327dd7e10329404f1727d7f963338d2b8e4f01726999dff76c0e780919757db76fc2856487bdb6240462df364fb43635c53c374fecbaa69f8e04e20000021c000000b011a69ec1a0ba3528553e6ef8e7bfc31d624c2c7b694a4566041ce8454720e26d9ef91c9e41d09123227ad0d832819c90b9ac84a67e5d6fb1807183934c29a45288538ae578618e3736c6a16a05a15bb3a56e7804d370cde440af8049e3db7ed1bc91a5608d23af5f166c3eb1113d14a02511b86fa4b279205cd5e195ebe7334bb3e87f983f90840eee486454b173eb010065de8e4febdbb776a75eecbfb410ee78f2cc80d8098e3ec8cc191d6dc74740000000b015256fcef347ff4fe4cd1d44b6c83cec2fce5fab7026c4404959e6a61398a72a9dfd0c6077c07c27249e9bd79cb3acd45a540e54ee9652d02f34008fee10e680d616dfc2f20004da97eec7058eb01f4f962fa203b1726b0466d0fc482484b745122b0d3a6fdaa00fec725d665072457e1095ff3e9f224d1109175ab661f68f34a407bff00b25c76b8cf1b38cad83736f2f5df8d4e2e3217d72e63157b8a8698536b56555411f385b9cb95b2ba5cedbe1000000b02564e7e0536742b2fba4e842a0625e8ef3ab3752ce269c26fc9f4fdb314d3759fdf7fd0e13145ce9fe8f54d69c257f226c3ca0695d89741425ecd0ed987b8c11f403f943ca4e2efb47a1573bc6eddf37cf05c7e286ba81abee0eb86b4ccecbf83399d365ff3bb48b68549fc77b704ef92f6db93146358662b1bd2f4feee4dfe706d63f1c79751fdf1768bb9072f337fe08ded528db6c94f8569fd9b13fa9ba7a9d715dce2ba61862dbb01e8e2af62c360000021c000000b011cc16ddcb34b070b3a1d88857242d2e2de5d9b9a91362bfa2241bb8eb0f054642ce6b12cca9369a6005544eecf6f7cd32cbbb9e7906eb7399171a3062ecd3faa8cf394d61fda2b605dc4f75a37181ad421b22ea2998cd20ac3a19736acd488ce3ca3e7d2cce4c14dbaad7c6afe3b7f5112f65aea923150dec877425e79016d835be239d129ce6480ba612d431deea9a10e3dc245f7ebec8adde440db1478c91f35cfa837cb4bbd0a6b3ca4f8f28fa54000000b024d7168c18e28358e93eacd2865e671deabfd5519c68b91b019a1f152a0f84e688aa2234b6009a6cf53003e47d12f5a891327cfca1f5bae04bf2946b85763b14e5713b96970cfbd2da14676cbd9ee6c0d83690ffcc7ef2f86822d872b0984eb27710ea0fdd7f2842051cb7877d6443a4197e8a3789d8103b56da357a4ffa4c34a2514c3a559f8b88b3202f1e2f2e444d21e5e54c0be2eb69ababda5be3271aaf26ad1a878551cbfd4a5bf6c7249398ac000000b00b4dd9452bf97daa4e1c21413b91935cdb8068e79cf55fcc3e0dd2c89994a87b4ecce8e8f368a684b77ddd2ed85052b8e59bbfd7927748bf4047d3ca802bf3253de841b45de8c197859844bc5f408754fab57eca90b0c4b9e96dfc500bdcdfeb0bc7379b251ea9de364aa49625c6c30f1ec196f9692404863e5c2b25e858bea8d30270f0ffdcd133a5ec08b77a8fd1e82c4d8e264dcbddf7902fc97db7734335dc8a23b4cdf93ec942fc5e9c3766b5840000021c000000b010dd1490e0fffb5656ec59ab89bfeb42f8c3604ceec99c0c2a21a307813c6134d1ba44ea4e4e6e6a89451ce8988e27e6377a75903a48dc40b93febf738151536b1310f759cfb8e6ec39e1b71cf215d70ed3a0d51c16bf93c31bbbc6a928a39f601be308c711993c75a1901aa9843fb471158d716a0e5a63b48e93f49a486c250e1ecd82bb6d2b68f2a6def138d25a91f0f73de9373f95119304d333463246ae4295aa2c2216831dab7df0d9a9fcb0ef6000000b0064fe5b1ef9be357d1c30f9fd849f60869502e8e1e35af0df4c0f9bae9d744f17fe66d881d4d8e2df7f890ce0da43b30fd34a65ca89239a1de1bc11dbee22b46882d5aebfc2b204981ddd55dbb118c841d0aa43939e3112bd6bd74630c5c533319a4f7b08d1a5e3baf9ab4b7e939621316df107e451e40c7abdbedcffc5d5d4009046da3f5fbb6500a8a2f331d0f1186221a6da6016423a1499521a8f19f4d9f18b2f3f8b1849000c844db1fc90c5a2c000000b01cbd09ff4192f70314421b60e126f885b9ad1e1cab9e3a3602a477832f261c0cb8ef25a5c058d5aa81ee88c26d741c4e6e4999a42dcf10172846d0242ae9214c99d623bf1398f13e6b0506a431d57ec1eb5da8af3f7edfac7a84171f1d8390c9e60ce61a3dd33d244c477d78c4139fd40c167068fcf2d93d7c93205728409195537875948348e48e320c757ac6b6039c0117afc94e486475b1e355345849822cee5d47d1cb2c448ec031f710737838570000021c000000b00d6061a877ca3338d40a19283f3c0225172bb45384ca587eb370646bcf45ef035ba4d874ee498d889c89a70d934725be2416131be922832286d018938320a88852f16c4784ae68ca3caabb6883088a132a050a5d8eb4d7d3b4cfdd876c0d71800cfbcf620e0e34075875cec9d0378fd526310dab39acc241b5ffd42d0d43aa5e24cadf7e5ab64170cd8280b7f5812e250acaad276cf670312866e260654d7635fa529c861c5b14e4e72921a35969725e000000b005ff1c4eb8bb5c577bcb2f919b9b07d7cb45a54ac2ee9ae9e44e4d10caec15401e8cb77403070bf4b8fe4b30946a97a01ecf807489f8dd6ad219420e36a1a3f90d75e29ae126262edd2b3269ef783381e1bde078f18e248da6bd0d50ca4b6f5f90df7f24590fe30f8aff447af5359bbf0ec4873de16aa8809779c48ea252c8989e365f2f0cd482348d28e5f2754b74dd0bc0fca2fda3c797c0253dbf7b4517a6f28bfa54a728b70eda3961cc4e87dc37000000b014564c71661a1674c8dcfac0014984d66cf91e4b49b4c76e004409c731ab51e09a8eababbf1e4b08be4cc334010e002ace7d48ceb572d95e0ab4e2d211ffe3b4e0f71138b42dc157f2265845f07ea472780d8fcb8e2e027fd8d37ab14d6192500c3a1ed33c8e2c9c156977e697dc1d651c2e122e6015e93c699b5c50708b253ff24bcc57be805d9814222f7816868ae123517260e77157afce72606ad3a5606f4b0284191394474cb2759f125f68aaf80000021c000000b0084bd316e61fd853fcd9192637179e9b83e63368d4732aa79c9a36a4cd9b8f28dda451b17c2018ea250f693ee5e58fa0a6fa42850a33c57e14a323594237da860aedc8a7df5159aa60246f0957223462a78273b6e0613322d84c380f3fdffecbaf55678e41b1f5dd12d894d01ffee3fc1754f5a67d5144b97de3f8e9179260c05d36fe1a7f5afa914e6ac261db5afc3417fb3bf096b02229abde64893f19c734721b6b73917fb713256019a46ab18054000000b017efdcc51672622bf30781c28a167100ad6f32f93bf0e9faa44b3feb9c1f7ffe38cd2749dfe5cd5493d2d2060eec55ec4230f05e5f76b37c07b86cf99b477a0edaed72a0f06861580f75fafa408a9896335ec052b0020982e72976fe0752b0ae07f31e133347ca18276ec5a822f986d32e1935039c868d7940b50cddbdf96621cb9093f5c516b9def0936cb734c220102d9e844bc94c8cd28da3561976c3a5111d04e1b45affa164e302b1a4dea72018000000b018adb9294392b4e909897695551f5093a67261937380f261b18647d8da60b08f3757a8b46f117880eb7cb4d8980b522845f4ed22755fc2ae67b64fdaef6143fa9283f140df9c567cb643f46ad458b07c1d814f4aa0f117c5dd149dfcb306588638c2d90f805f1783a1d9cc47797342772a76efc51ab4185dc811bbd55b87e526627e1e3571b7102260570a1fb32960ae1bbcd2a9006587927c322f0db784c4ff93037cd5c9b8e2fb9def9a1bf2ab76820000021c000000b0121e375d79dcf8e47f452fbabff05956a1f2bb33fdc56e50caff4278b3479bc63bfdc5b3a4cd7d7190a3a80593037b648425cd96d72a15a355de66932ff5323fb099c9cd4e1c37c839078d267e1a85f773ef2917505e8e9e94c84c98910edee2f1675bb4abf1a83a78c1fa2003467c9e17b332e0183ba82cb18b900442af27345847a5ef09dd345915c90b7215ff327525f074124c5885d3687e238db78c51705389ec08bc3538dedae4cbecefec08e7000000b005dc3288d5cdf30115091e73b4a7903bb1e3948988658d172396c2d55fb2c66f8868156424eedf6985bb9758a58a01493253fa707e2682e2be427e905267e118cf464fe08b9cfcc31b60ad8bddfbd68cf4403eae54b9b720b88ce16381c7b563347ffdbbf2bf53842d8c9868ad0a99ce1beae60c69391c82e93bad74bff9c51006b7dcfdcdbf4d4e94eaff69446000a51e1440d5043aeaa111f2a4ce1b2b6be01c2e5246d52f4b96f544cc81282edfab000000b02d915ca32fc54c162cec50e458f12d40b97fe73433e6d923cde0017d8075bc7c8a9310630f4dd3378a9b96339264064b4bb61d6d13e06e9b42e5fa4246fd293bd4b06e4ab96fd4069ab7cf001c3f3ac807d808bccead8abd53e43a7b1a948af4ab9436ebbc02b14717a351864d8c9ba52f026c0df9152066f75ec9e301c09458a394d9af888b3cf0a48372b521e5b24030037210e76592639370eb4d98727bfa75683e890ab5f89e07c122598bc95a840000021c000000b02d6bcddc2d72eb1ab1b9f82273b8b0eb0999cdf6461704af3bf78f9ef265678a2b09fa37cc0e266a91833f01d05db4c22625cc78f0024452debc95aabb15cd46d6130705a2874fa53d349eb02edd1b177949b297d2206692d8069b8f7a4dcc00f3e6361247d3f304e52423af435beb212d9b3c99f191d0646c03df89a90d7e6db35c14e2502922ad200234cd23bd4328047c865ec60fc24eb387d4c998cf4b469f30e8d1c755bf3e5befbdfd49f50334000000b002cf2801d3b5cb78f60289d03a5634610ee88c7d6ac3ce8b21622d37dceaf3518f3a04d4a3555457a9c7848c65ceee647b94cce3bcfe268d3353112b47774b1ce6176631e94d028d16b942237be0af07ea920f280ce2d0423befdb78eda48d2ed104faf92f5c95365f6f2ed04231d6471c6d607f9afd8ea6ada4169c78e60a544ab9c56d9b9fb75062924ea98a159ba9222b3a422cc83370acd8ee740a7765f3859e1d31386244f4e1a469f05bcccac3000000b02a17eaf79e53efd377896816806eab246ad1ddd8252d4ea3841b94373e3ea86792610395f9bc4b3a582b96c513d0d8ca07acfe483f1185ed8d6ee61586ab2fa5dda7fa6584e61bcc41f19ef754c4179101400c5bd6f15eb4effa2a2682981c1e79302c56fd1e8a1b3ab63f32a4bcedbf1b1c5f6e01de5a9efb147264c691f6c141b31b7d1a6399b1e6d55f6763cbd6f62f958aa766fe9a8575d2317bc8dc282cb5b4fa68ba7b14ba83af5d8a99cbfda000000fa400000168000000b0108780cae4c914143d3e99581d25b9d1326a553b6e50d7e64356d74919d4f00a1b3439f8980e991eecd513019a957b8f7c65d3a96c1eaf0e33a0b747527ef808bcbd2ecc2ea639a171e20ca98961c5c62ed3341371b1f03af612dfa391192e98c53ee8e86029efaefc9d09423aa8b54017e0df76927f8ef9a25f741f3ae8ae3e200be492742b94de5622b24def36b9b02501beb30c6afc30bdd9b9cbb6c505d0069da4f16853a6129cad8df9d63141c1000000b02d7b134eb468aeb18af35ee432f25ce995c349b9f1754d5c77cb17558366ed7ff68886d3428e2e3b834895dae7dd6f9030e1b9175205fc9a866b16de7e4620231e6551c1d12f1a21934dd7081dfe97244934cfd2426ac90b3b2a53a315054d8f51886007e1fcbe7e8cd65c0a94742e0e0604cafb011e48d65b0b38f8999fd481e18b09e0a549bfcd8c3629471b55c8a91390a2327ed73b74f585dff8217835ae9d8a49ae8f8c9001e6333dd5b1123bb200000168000000b02e07dbb600ad7347778a5a600564b60af59f090b5615d64661bbe73e19a329022ee0ad02ea2555257c3ab2095fdb159aa3bffd5627355edaea84040bf78633540f9c9574fd64c229d6865800f4df68edb9182c3d05c67376498738a2479cc99b93cf853ad7fad9e1674394812c98cac40d062a7ba098049b4add131eaf2d9fe7c0c7bd63759216014233632813702f9c1aea3dcdd96449533f4f40efeea35183c0cd8430eaab4fd59c4f7c395b1c26a2000000b015bae5bb93926bc81586bc46af5b6e63bc6dea1e5d8608ffed80cd55a2237aadfde5225c2dcba7a78ff571d9f967978c6e156499763788fa092466612b4f579a695e6a22bd146438f87bb329795b6765c2639828e197d928a701b418d7eb730b3326bd63af865237672adf0197adab9528f3851d600814cc04c0a82ff74ced504518baddc6ce7cbe5b891c052c0bdb1201027f8954cb7c942eee675f45cfaf84a18f1306005b8a3f53bd449c123cb0e700000168000000b017c9dd4b77f08863fcd9ea0470ebf1ba3a9d2739e23ee7432b3422bc3a4f46e9892f2c516490895ce28ff1b7efd454061f95ade62765a79c890d2f5eb4adf48da198b62d78d8c0e6277fdc2524095dea10594f3cac81dfdc97bc688139a6ee779b208fdce0d8d5112399c305ee7e7add2ae1e71ba68a733180b68941649ec4cd68d1da4de55e730762cba9029e2be80d1b359cc6e1688b9b9b53beeb0c3c5d535590366ee636ee4521663dbd5f047ced000000b011c3c5aa5f098456b4d68e7fc1b3bc168786d6b1ffd82bc79d6b440cf8dd2524b02c7cd90e74156a2dd320f04edd26df4f77a5018bdfba0bc60d3d0ae12ece5a26bf2d71b9f032ac82961320f4027077a504708d8b5c6a1f19904575df03e3921845921ce8bbb8b378479c953723d4bd1ce84caed034fd3cdb74199991bbbd683ab2e6c440dacf7be6183c6a3de5ce0217bcd7b2c1ad5e8da967f42d64d6a7b31f05712fd1f1bee4ec4889ac192385c000000168000000b00b06bfbc8b7f8fc184660365a97bc4e7ddf99c9b7d0b4a2b814fcc452670f9bb23d0091cf0a5c07d87a93b0812aa59bc46049495e49494989488f6c7a9d4703b5a89b1b91ae835b3fbc117cac76dd85431680fba394b9782e4dc3a6fa25edc8099d9605ba1282121406ade248028d8aa0b9d724e1967d330be32d873f4858efde74c97a2681b775c02dbb4a9e8bb669a0a74810edaacd205b0e29fae33f546b9529f1f79ab6f3fa9890d30573224ba55000000b00e56826ce4e10068dbe2520ef88ebcfef9f987599008cf1fa80cafac40ff4f1749b291b115c51676076dbbe0f4e2d898b568b3840bb708ab002d1c725dc89281402db9eca109735a8e7d73a31709ba6611816c3ac00cbefa5b16b6b44a71f65b1d7c4cc0f6a42a2ecb3db25e1f442e142c68a542165feb07d9d8c9f1f38a9f75ed5e0bbf5bd17bdbfe9b5db93294263c0b2debd2238f7336968ed13f86ad583581a411de8a4295a412409d584f49df1400000168000000b01a28e3222672321b2c5008abcd9816d3556ed1a3dfd923ec5503b0dcc632317c996724e8480431175686a096e2a9188acac72ef53779f45f38b6493e57386d58cec5b0f2373a7645124e5a9b1d0694095edef9032a4a942ad2ea02d622d6b37181abc08806a3deefe122654b56acacdc2c6530bf95806a9fac5567437a9683469e26a21336dab2ca1acd8b9ff39d789620b6449df0a385dd57e8a1f99f07a222d14a3d023bf141d89d573e92565cb87f000000b01bf3c86d67689f6d5e3f60b14d58bf390dd010b0aff2b5521c9f12754dd4f2838eb51427edb16e6cbea5f5d05455bf98f1181b84dd96aa9f118e14f95cd92a7ec2e3ee8058bbb2811333fbf913c19ad37c35c9339728d12979cd7b8680e29887988d81df17e55a9c6fed2a4fd3fec21124ed7ed42514d0cef4593c09e1b6d167569f0ff3c3feb688cd8df74420f4c8d52ee2b83a11731b3de6dbbc5a37a703fc7346a808380bb3c58b561bbd3749fcec00000168000000b02fc2ef6702978f1585440d800bfaafc12d4e44dadde0e836f22feb57da30275b2807bf0a8eb826ebf8bfd0e14887f801343dfeaaed2e1a5ce47a2343bf577a68299e96ea5f0a65777080db0116e53d39557d1d8048a25bfa0f7cbccaab06d5d0cf911dda92fb8bc52d7aa619f4f515d4157c54cfa82e9e9e1d6facfe757c8814a3b52df4a210cfdf65e54f58f5a4ace80ed3e2127936914f21e2e8cf41ba86ad2aca30d8ef01ad34e6b4e14c6f41c56c000000b008fcbd4c9523de5523bd59810a89093fc7153f8df72353779e8d695fbc4f7f56c383fb4838cd73b20fb931677ee53d5684a0301e2ed435330a8b410353426e1f3ce130636588638607c20bd2f67f8ba590bc1194cd66d0909e4f535bfd9b62e20002e96c9496db143622a4ef75449c1117313b0829b0efd292e4434e403f08314f1893410a83a1d99dc3e82563a7461d199b48121a29bc3d70d2f0c46df7f5236f4e25ab55804db2d3e96e56feebaeef00000168000000b0287464ea51c3084ffbc64b1fb437bf67c35062caa5b51c412c7a3bec44ce37385a94d096a33a598abc61c529c33da132b0e67c5d17f8e62b850f11cb395f4bf609764576ccc6725a0533dc48ae687e1b4f498cd63f9110b4013dc4818f8bba58be20fe8ab24cd4aae134310e5fe2ac0302ac07287e535ec5bdfb0206e6c865910b9f49f085fb02c19649a382deaec9461ab7858cace1e9d014bde9b17b52c89e2755224118696dee83e61e5002e995f2000000b01779f2669b38e8c0d9bffd0b1430f0514c42bf80e1badd033d7e5f832d1d96b4776ac37770141b23775e18e8039695a412284d138aadccaae6f934e1ee2dfbaccc0ebe7ae14aeb97d5fb8f8e4aca288712f21fa28a28e7eef83c60fb30555c1b19960ee36e76d69450cadcf8e1297fd1222a92e408e837a41ec33af47001c804bfba2ea7ff1265bc291ea240ac4f726f053d7d162f0f1717e5c5cc0dcecdc56e170c27fc42d3107a488dc0f6c83d715800000168000000b020df59edc6b59811084e3ce6d7354971e82a45c6fedbe6e79f680c715470c85304be54ff1eeffc62213930421592b2ec9dcfc1d91a7a2eaa03ee6f3671b2fbab243a2e4bb43e7dce86c1f3e2e2027f9f02eb51726f46aa1c8b14f0981cf08aef2a6004b1df8ce85b8e38d03e63415a560908e942703ba493a4eb66f1adccd939caa20fd2aa992e50b95ead77b502d7bd031a7ec739b150bbd900dd1e29074d6c916d65bacdc947dcba29ea80468a69d9000000b0205478f83dac55d701a787f963e64f7aa51dd547615c9d2353ca17d4554fa2a38e73bff68dc31fb6545540ecedb4278c3fbd541366bf22184f8bcedb611be5fbc05b60d77542a33372837d639bfc90535dfa96f25d37a2d1db13c77a9b321c305bd99dbb7669a73d8cd1a5e5245af50d2511c1c332e72e7b2784a73a594d9ad4c37fe0df734fa51ffdb4255f0a77a96f06c2952de69862756b7542573b2d4a8e276f5d632099553f3c4c44f3a8467da100000168000000b015e63cf89c7cf5a3a5535bd553487bce43ce213c06c953ca959b33386e2a9f3d4c29ebfe92dd6a0e674e840a04a421fb157407d378ad421ea6472df79708df41d8fe7da0463042b79086cb7acc4f769d1d5533d8dc880e83574ef60e7f272b8ff41838a1c77ec3b6ef1d610ec1b3617a2fb4af195f73c11d41977cbf2474d09cd03645c31e016ddc45b7d6086b0484a81a614e1b76974d01caf63fc66165bf3feb64907aa50b54439fcb35d8f6c93783000000b023a47b4d1494625d6035530a819f1106e21de12ed5094bc44d70eb7359a8dec1d610849ec348426fe8c8c5d697cd7b81468d69e3829983e9774356465c7aec21a79e6d45b4b4e5434fa47d5036f3ce6e09ce6bbc9b6d99de50639762a41f86f32d1e6f385518f832f6ba3158ebed9fed11d819cddd6723d34e460388c22a230be919708d0e8b46edd25d12cae4101cec2c1150a9b302a8c2f5e6773a1dc2676ec7d81af44cce5f0ead28ddfd64b376ed00000168000000b018d85b67cec8ad77ef5aebe73dace23c4e42e91c433a26629f77088d5566191edad32f0dcf0108faaa5b43e49cbbb0a5e58dc5e3340db2578bc349123f09ea1141e850722922d14f355ca706f904165e31d3a09bdc851e0c6a63ea5fc7d1f7d7c61d5fc8c177fd026c8da05c212187db052d80c12f87db76770dc8e42fee08c7cff0511f861781d3c0ec816d15d09694156f1946e34835ba95fc4e42f269f19b21353d5eb27e93389bd459089722626d000000b02133ea6eb17089329d84658dda3e5e53792d89972003d059edf2f291e57df2e79674c1c195fc7ee3799daf0a37320477c1690a53124e87f1fd3a2f352b3a7c7268dd57ec2c296f06992a640876965323bb12e8914bb820dd9325bf5b763d71cc6d2f74c7fa4d694f1bd46bd6fa21cbba1d7f0e16f5bc61713dfaaa3e9fe417eb023d12b5721b0499e525eb0aa47f9ca422c12454e68fa74bed8d7bede94e29079e883f09d8fa0f2114bfb36705cfb74400000168000000b029c44f61d6448d43b06d00e1b202f918cb17496ba7b77f96c3da4c1f31ef5e196bcbc8b250f18482860b34ee187e7c316e3d2bd117edac055f7846ee93ec13d26402060be73c286449171a8115f8297aa8c8f8bc2d0cbbf263ab7a031a824ce5cbb5a5e28788d576f5216c26065ef54901be83cbaa2bba49d163001f9aad52f47d1a7d078ca07fbfb12b8c3f836e99291e6ba770536718c47f358cfc9c68d504a1e8ebae4600d46506313a67f4926a3a000000b0072769c4bf32fdf027026b7d2913d66b84dd24111683dfcb1028b778fedfe0cba592b03808e66fd546f825181cdfc48df9efab7260475c5e19826d9fc232f442cb0301a77b4d58031e4a017a33a54e506dc58f540c0fa4f014dd11b2699bb2c318b2a271acb1d589d3522d49f9aacfa3068471a09e194d258040cd41a781a4eac54360cb82f88aff03c3afe1a093b8ea06b6c9b9778f8f5af5531fe11ee02f20fbfac6d10e1e3e08104596057558e9f200380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b00c0163ace6c820b5419f0d68837f0c235e3d10119376cda0252b739c03a9d92a7c7d8ff878c3b407604077ba839e2b87184f9c5696a5ea1efd8214dafdb13a708fdf891f0e0aaf372b54f13034ab38bb8c97cd2088ef3fd465c860ebfded20a51828e62994749348ee20b10f71a496092db63ab4ed02eb1f10a15d1ba4107032355b27033ffb2095b035ff1ffd7f48d1182453f7cf8e6e3bef27c00808dc606a32df4de5055ca307845d1f7ab4fb213c000000b002e830464a24915aee9afd887352ccc6c4a1511522652fdcb62fd716f74efafa058d8739c40b521210134ab9146d8556b43422dca5e92f2ece59a2ea28fe26f74b6df0e49237b71685ab4952edfb47c953c015f039474a34e8a00b9faae4700d9dba4e3be2e91736e031c1b837a076500958ca857bea650788975f4170b5efd63a4686f2dd2ad8a07da38634d20ac7d32eb44f8600642d158f1e3d8b59dd26e30198b48dbad0c69bc4c8b7ba0f43c8b1000000b00cc6797b8a0c661c2f5201682841ded0cffb88551fc784161d558baacae3b6cc461c3f718e863030c4f936e31b5183c1517637360f0df29a120f0bfd14ccc326780932df34445d07c0d053fd4c14e912e2d44e83ddb5a931d1b53721b453553a0646aa996be23565a6b64d87ecad149b09b8014392afb5553cb67528bc3b42fd63ed2476454bfff4b48ab7874ee8360e2186a85131dd1edab9a79e7099ff9b07e1a0bd28b7f2d4e296e204b95ef6ff700000021c000000b02b4027fca07dd252a6b0c1555105f0276db0abc6c0e5f178bc9243507e3b3073f4439b298af9b9854b06af7388bcb196e354ccc70117c1dc1d5294478448d9fd11f71d5b706fe55e4a41dbb22b78f38395064ca8bbe84628f41844b5077222a9a5e9914aaa74b68961435368e00bbc3200a21810f6b6bda1a787066eb284a7367a7ac158c2f0e2a873da400b7b53c5d7216944706de5f27aed0d4453becfca44f4a4f5773470366028c3caaba4459622000000b0173ddbd24035d8013325f2813e13da78dadf5e2e4500d468582e7e7547af7ab560432254708a82dec2299ed67f9ab29483fa439aabb57b41b0c4d9b6b7f3fbca2d04335024848640d9c47b5ada5212b3af08e216f65c3184b7ca469b66978e742b3dc5d182b298d029357274e73dc60a07f7ee909753698689e19614cbc8b785cd0282289f90e92ad1bcd0f69620b3620ca3973a039ead4fc96134d54dd01d0ae5be671ad13f32feb26cb20383cb8f9e000000b0047f07658ffa7ccca81dce4c6e9e28d17d3929b65c88e997b457d209e1620a5b65cf5c40ee5d9b07653752f17e5dffe1621cb1a746b88c330b41f28707be2f0b9dce6e73a0ec1c587354aacf4bf967b4fe4905a3ac4d3eb78ab7bddaa1abb844dec30132147f3eda1f2a38e27922bfec1bbc3293311e415dd18ddacf200c1299e4c4996d6a4f42dd0526cb63dd17c503124ccfc06d76c240e297267b84d8dbfa6b39dcbd7a3b89319b87bc8ceb4a5af40000021c000000b0226ae8093f9f958a97709b384b06154744db47b70cc47346e910fde67d8c565e66c9ea84e58f8f9b0b855e7ae6332ea321d85b3dd5fa8ef75b54954d2c975ef5e093e40d80cefa50b4db9a90343ab8ee015802fc0e4bfe5255e0a3837aad44a9d90c76a24c060daf8490025e030dbca8259680c303d7f7a9257f4d5d09eea639050081815079b948769421631f0b5d581571dfa5d0d2c20cabb65356d130e1dd1e406401c02003aeb4932e9341a98e8b000000b00f5ceb408301df82115232f6b151c07fab66e44fc2707b206b9b4002272d1f312e7bc745c39a76dea3e33a374f036a905a10dd6527f7f2f000c838aec815ac98335ed3a86d616af13768b63480b039112ef779afa95ebe44947d94fe8f0d0092f7e5207b3a59490557ea51c3f5ffebd51362e663bf9150a0dd0f3a59769a119263c8f606c33c840d96be8efc13a4a2a61c695a78412af31a4c840a6301afb8a336d9d174c0cd3c1dff5af855897b60c1000000b01a19b2654e2bc73ce95ef2136537191905feb588489a56a74abdf59571fb8ca92df181fe0e8435957eb82b9a78df15f4f54382d5511f914e57a7e4672876297f2a96c43a331d2af468060f2a745de193a094e05e0bb46b34633ff9de268ed2a886a8bcb458e1d93fb36bec80f3489c571215d65c9244ec8cb8cae7fc3d563628b291bc20cc218d545616080ad3dc27320d6ebf97d2c59cea88d5e7473fb2f72ce62e00f82dfdfd1fa9e822712d56c1230000021c000000b00839570ae6cdc597241ee9bbcd55e0836d03c390fdf0fad3edfb5a5be798155fb4307f7f83b810fdfd03b77106aede3f5f28c96e48d19261e4ca4d6ef6c2a2536d4b60d8b390522c0d2added812b785a5229a05a374231a2dbc67d09a62fef973f146315fff26e151a81ce7a94b49651117ce20a8d8e9200a9eee5479b52b4e386cd9e09a5706d043924f2aedad5b6a10f006f53814ea4be7303c760a0938216a74d242cff085ce66ee6541ffcb29e04000000b002a8810adf9335b62833d20c39b034339bf97efc66037d244362bf8e74755e8c8c03e5c249696bc110bcaa1b100922f3b9a8a35e0a7950d95bcefdbe6fd93b38cbe20f9a861d439e9e2513f1b37632b28c851af10dda5f9cdd7eba1faf5367999baa0fbc506498a5cc52ccb916de15822a1bd5af017808449eeca21501f08c6cd118ac07808379b51c986c3cee8cb8722ee2f85d4f6bbe1130f2426864b36c59bcb4e1908dee7f010a391f198e4dc34e000000b004bba465ab8dd924c3db13e8ffddeb88ba9d6419f446b975d86d30de6d1ee20815e99fdc37483fe632511c7e904188acd049820587e198a68558a7433e3a0e192dc90459ced46c167310713898020e93145824b5f60000ff4c638bda042d79dc882004e65a71ac85bd4d99d0531265840d5cae9aaf800321af7e7f433a58b1c3fffd4c385ac5d67226014586d768328a2f0926a3a1f70ca809721437e8c009d4b6d9c264d892eeb1d63aaba818182bb20000021c000000b0305b47c477091f4bc3c08c03774508133133b80e037895b4c8f9f78b1fc1f48af77aeddb594a6441735024e7a7606c06d3555e3e9ea57492d2c729d1aab69c6802740b6ce8eecbd631d8cc5e6bf7fead790973d1201f94498e694c3c03bd42cfb9b3a2764c27782ffd63e71e435a46cf15ac35d64dbcd2c738c09c8fe74e0e94249cac4ca08e292f728ed6394b4454bc0aa266b61540fb730d1ad40f51860b6b482105546580a7d2b9b9ce5b191024ed000000b027afcda05c38fc1aaddee99553cb8e4713c7136218eefc7329cacf5887468e8aa2d83075ddf21e1b2668361610cd8f63b12170e076792443b90a797fb3f1f17508c550ff442124973d23351679bd826fe7d730b3b33afd3bebd2eeaed4c6ae3e46dcf3c3d6df0f357d96e4139b2b029d215b34cb8540ddf1789776114d7b6ad750011f8c4bbbc2033a38572beaa115b72d02a63e1d961824b2ef103cbbc5641428ff05d5f1411dcbc8f38bbd34aefb0d000000b0273bc57f4aefa6a17ddd8b9091936ef38d16b48b459eeded19c69f564dfc9c5e89dc55b71072083361e80fbdc185c10287ca606b310cfbf665764ba9f43f9cdd64d50213fe5d12269c9c4d9f6da8b3bbc019f8bb860bd9de54e2bee8a43fcf9206cf08bd84aa26b14f74f9d19a1f2727258170633570f2e4dde3714256997342d558394886605313be9280892e3785161e76657d95455807d573da840d15d2f1700f61c1acccc13ec5de0c07f4c706ea0000021c000000b02dfa4a21dd2dda4cd6ab24408390a975a5341876cdff88b72c3d0f410d8c8a4ea33b95b6905abc0f7010e94ff842762667d3629dba637edbfc5abd517ef0fd69288be89a0051d7b8bb53b8b7199aea9a9ed5f702447b18ccd0f9a7c570c6c2725e79678e994a1875890c50ca03f57d7603f840291b8bce4a8bb622abfbf1031c0e07049691df588b101e11d06286fe6227f46b1c8689aff3d186eac35debad499ba05f29d6560d979bd5644890fcaf32000000b02ebb4ab24d35636dedb98611fd2baeac5d6a5918fa5a837ece7350fb43a584c00982db7aea4cc34ed6bd917c134d35be050cc200826a1dabcdb7bedf7c87570757e6fb02683f9d4b2f05ce513c6e4e6657fbc9816dbf02aa9743b2310133fd7de2838469f6c103ffd1ab3a147e8eb46d26f5866ce5c0c2dfda7a810f1316049a92b0fd8b4b1a46b4b917bc2985ae94b42dec3660c4804293746e2a7f6c06a5458f1f4deb7441abeccc130b5079fd708a000000b027f7b5d76a62113d1d967edf1b0def9cb10c9ac30841187af17616f830a4667e2ae9a11b890a5efd7d29d0d5169e023b481fd38f0d2fd666e718c1598e39e29b9154e75d28aa3769cb7c4bc19571e6e59758fbdb32d4eb097359f7cf8974574a642b9ca9e7b4c091d2cdcd9a8e8584a90326929b661bb260077ff7ff96fdf729beadb488fb5ae6294602e9da93b657812101209e0b5f1b169c7542b7a8bd8b852c5bc86c4d43ea23fc2f9192f36bc3700000021c000000b0282013f3d9e29812b467467bcf50ab74311f8dcba42a66898c489014ba4b60f83d176fb1c88dd0ab6ca7c756f059a82d3d0c3e0d46ab57537c8a1ce5578acf48008de7f4d1374a2a9ab6c7d20cdc51291f225bfe1a4bfd377339c167a004a727bbd5237414462699ed85782b4add90e5017cf3f9a84cb3458f83568e9ad89fd543c6ed153a84e038496831b5c7a3013a08c539bd3c221da0a55e24afed79bc2b5b0af049a4b52914438a54d2cbadcb0f000000b00b801caec1558a7472aa4299727ae3f394c44b814dabaac4292f0605b4b5941001311be3b23f92ba3eb660f5ead89dd14058c853b7346d60d62a5436307873ca5f1054a55a73020ba9c1b0c8991ea43822f1c140f0a9ad87e78f4fd34bd0a9c6a2dab614af2a1968ffcf57a72d6f6e4a127ea23abd3c168c65a7c814f8bfe1a2ed3893a5e5fdf82d0381f838dc6d972c0a5b62d808b56eb90ed746da789f54de6833968818e0f79249cf4bcc9703c01b000000b01ebca2feac7ddea430abc3d7a4bcc836113e86540a4ab4ed8ef0ab2611f30c337b820d0e9d63ccc9d66d4cd3543bc3ccb6203123ad70e2e5f929ecdec8985dcc0ecae348b95c4e77bc944fc1b49559a222e8a8059b7e0a225ab1398de32b3e7eb576bcd711e275c0051b2a54687510641e515be120590d14d6bb400dc526e27099575fbd3ac8aa9ddaa2e0cd741a1f402029d7b14b5434eb818327fe23e65c034a91b9798f6654048969c021354c4db80000021c000000b002326f53cbad3d5e6f2e5a157f735e67aa6a75eef8e423eb9b2df18417605006dd875e8ca5ea451ea68217a182eb5b3d716bff7f16f35d1d253015e1470d90e73ce6e39555707f2478f7eb168c0c6a9648264e4edced7d776eeddb6abc600fc11e2c9708cfc783a27d1e54dd33dddd8829e7e6868f747f59053d87365256a7761cae602609a8b695473dfcb9e75c6d9f0e05e7387e09cb71585a27f5ff186ec6dc1b4e27178d4920dc0cf6bffafb97a3000000b02ddde8aff9691d48a25eaaaafe258b89cb2a169e002ab5259513d8bc80587eea66bf30017c8373b474ecb1af419c5d54e278f90c4c0dcf4e0ce71d263cc84cd0f543d595bde82aed72922c2fe135802bf5991ba8515335fe5f8e0f24277fd66c54bf2ff1a28ffa0c6c3e35aa30b0ae4804a04c1be3950a730a929c56509bdf5daf974e3cd2882d6cdcaae2ad37a1a7a0122108244026571dcbed28d71b8032de9780693162180fb6dd74a9293a317459000000b0272cfc810b7cb709f818df188322b786fd4703d897511d8024728a853957062dae71a29f25ec66d37fc471b385e166732b8bd7e2adde11278ce3c6757492f99a11c3978310459ae947118207e43f23ab3218542a1d9a1ba122736789aa08b1472445c2f3507fc42e9f35c7948d20520e29a207c9649157c6915fd74a19342854026091edfa8ad8e3a584d62ce8e081892b6b5b4fb6cb02ff821a61becf2e883681c8be0e51220235e601f516702a62aa00000fa400000168000000b029cc08d125a992822f5f6af1a7095aef6c1b85986a6e78352c657d04ad3a09c76637abd87feed48e67d4de205b6aa8dbe70fb409430372d0f1baf0ff8c7e5a4055d65d78e7b1076d7304e2595350bc97c6099f548973c4bd0a53ac9c41213785ff95efe438ba17aa0d80a0ab15d684972ac73b65749a5ab86b8799d25690d4bf79e47f5de81b6ad27a5a65b036524eeb19e0228297f207b88228ad8b75059440305a416599d03b2e67329d306794c34a000000b02e262de06a68839d00787aa1bedd718f2bb1a15fae1b9c1d339c40e34685f25d74d3b6b0bdfad7b980c25100779cdf5edbca71a96204c209003cb906c9a8d12cfffe04310f840020a8437a01ce78c901fdd754b7cc76483226c778a55abab1bc61216a00f88fb823544a6410b8ac9c9d0910855dbdbec81c9a1007746ffebba43e74ee6ca4d9b09b1c0b5e24e0f1fb90222715cf274fafbdab56839cdb538f356c8ffc2663e562773f6562443632487a00000168000000b008a3b42fac167bc707bc353e8b660a4a7d0e48e37b6392371c96548dc2011e07cd9eeda1209c741cb16da83127ca7d35ac70fcedc950afee0b4aa991b0904aca5a7a07806e0afd358b0c8bb94e1239b63228693b429004aa96ee547a02f9a64bce0d7502a2a8ee906bf8b26443918bb12848ef078dc4ea7343726012aa53f4d10faefd474af732560f9b0aafedbc96e206053ef39bb6ab5e628e7c660032113ad259c9ed6fbb52c64ded6e63790b9697000000b0006070e5171b394e4e301f5ea2ef4626b37dc18c75505916c19eba0f6b0238ded34a870edc3ad6aed91cbed48c9773122ba5f20745f325cbea3b9f054d8ed575c344662412eca810a474762312ddc69790e6d3f2741eeacc305696bc5b29ec93ab91e6aecd6540270e571947f09faea3095dcb67367a6217af644d5ffd9bfa04aa92e8ed679252a0dcbdf7b14a1d883a1e00a4b7860a87b9890381bda1eb4240265304b28629cba0709c3ea84c4be63500000168000000b006e0af21f3e056014ad8f4794c94f20d5e2013c900c9f8465e8043ecf8ec7da9330dcfbf2051755f18219ebbeec58981d973bd99dae675393a4f247a5b1cf45fbdd5be2583a0c0a0efcf90fd39161f6ef68156736628277d0dec910e1dd47425997831c78aae309513d7d4118300e9701f1972e787cf73835ef7efab4660284fe319d7e70527c3f669309d195b97e35d2d0aea47e7621c6415711785efecc187beb3cc2b55849b7014eb343df09cf5ef000000b016aefcfb4ba34805d0b74e650efcdcffac45d5beb78714ef6698a1956e0c6dc82c03f2f011ba145aa3f68cb0bfc7b8878b81d7b08fa51e5684a44e66468f565e672cd771b2bcec2b7d0be1475d82cc3088066a074713933dd6820d47e6c3e3ba6e68276467066eb8738b5b25817dd282085c79b57cc1bb7ba82c728697f82eadfe223e44e88e769175b931a723b9a14026457391f8a947c9598c5b97639325eb5334712c71b5f7681f59cf7d5e71680000000168000000b007d79c8a63273c2503fd7adf93c552885ff9fb3d75641039d9213d7237db6d4f0f1ff48b02876527a3bb25e2d7d5bbf9f3ba798b24b4c6985bbf5f437f262268fafe4cd7e843eb8d3c9b5101b5afc56db814c477c80ee2b21dc3c815aa1298389edef419fdf6830d2ed3f310543cb73323c5eb474a29d51622a4e46518c839c68d0ddcb3acd3db6a644fe84dd2ff6eec0d95daa85b8b34a29684490f7baa0defa439d6a75ea98b44e7e3f2690e20bf9c000000b027a21b3be2f26f56daf3258c981e45c044c897de28e4770c73076905a938d7340faa918c9c0d02feb8d5959a7e85ec84365db45fe6324298ddb04698b6fcbeb0c358b363099e5e215bb913d172ebd766fc339d69067bf7e324003e8099a7608125b297a5290cb36bae49ffda86b7dbdd15773b491acfd06ee89bdda0bb207f6e18190c71c450246915cd30ad38f2efbb08e9760cb4668f93975eed5f1bac265735b8f9502f28e94bd8b530d2ae49544300000168000000b02b4389c4252b98d2b2e793d850026d0e555ef7f043b00cad249fce3cc56521f6a7438db1bebbb8aa8d8a67eee256882e3dddc15958cdfae658ea5a23ef2a336e3bc4af67e70c5475145c224896e256d7e5f7f43bec37a3f7097de9e8ad48216b54ce58f4630bf5849231a65b7645817523666bb0a449189428d50f66a205f7ce7f42291d6a24bd30048d98a8534d10ff10c1c498ddba43323d49737fe5051674f8ee85bc97d1a432f037d8bd3dcc1636000000b00768c4bc5bd833df4f79aeb7acb57c3c96fde42b6ed88bbf6b48b68a98d2aadd38e2c8f24cb653ab4230715529d1129f766b7f5bf4b4d619cd6808730c8e8ce18363d4494aee05edd80a9879f2024d6f8187b47b17559a304326e28e3c0b5157286761530c9055ceffdef5d463f4da9417efa9f033e97e448b80cda97eda81be4ce8beb3be4f35f22ed9277b845e2d04244691a82c4bef544bafe6e3bc9fe8d259196818e925bd490561350456799d4f00000168000000b007dc7ff98229ce22ab2673eed239a7e1f8ef036a6c29e24a64772f06d4c25a65e49b4e68880e3e71e20ad1d899393a5e04a85bca635492a65368d7b780c65abf10378887668d9baddff28c7a29de5781712b3bf138506781a8049dc6a65f65cd102887e79e99778d615243a78870733925ba10c4aa7db71a2f50f7ee50beb71b61c1d94b5f0e0925eb7509ccc12a80f60b1f2c6cd87da8e746652ce4f096126f70e12bb7bf8f47c9acbc769d07246d90000000b00c4327c8481cfdaa435ad65d5adada24d863432d395c352f6dd5776cdacaf19255c4935a6277a4c3b60e67409dcf1092aa643d2aa9a8fc0f58188401ddfac0ab28dc6a142f3f50fcbc9cf114298c66691280115890f08319c5e043664feb9471bbec37c8edc7b5b414f0befae87efd9b30412732648e93814125ad5986f21242226e3be95f30e53cc09f12b4a56934cb17f9cf93b7377a897c0d2a9abc0d9af1bc968c6d1a082b50bd901e16250e395300000168000000b00a6f5fd1bc6cf41dbb48301f85f7aa4735899451d356447bb861b00ed2751f0136935de52217d23b1aeaa91f310525c030ae10f9043b184d6a0d5bce4dbffe391a325a69094d225bb9f4c48ce115ab3a20761432724b71f797aa2abd689a2506c71b14fd2e97298797ab1267d0daecf624c5d7c24cae377a9fe5b1a8c1aa29ffa38a31b6ae98edcec0df148982d902f40ae2f2e6cff9e4a431563782e2206e626396712ac6b543646b29fd3be50b8b17000000b006ec5c91342357a49f973774a61ab514bdfeb66972fc2f702a825cdd7a2369b21f8c94d84292a0c272e118d61e8e09d1858f7f89d6be6b424f1379d3f736acdd4ae5572afe15abf6eff0606b2abc54ed0f6f170260f47f48a5284e3f72dffbe7a308d6ffc8ca820eb58ed488a6ab03ec0c072e042ed4a1064553ea2956449e4646212714ac836399a445cd0e0bce15c0134669f7ed3d667c3166e845de652ebaebe8f99c65d4555effb102ef0d5f175000000168000000b0145e3001839a08fbe62f4002fb2a17860afff6b18c01497e7752e5fa3b991c7f3bca2cbe9fbd552536910bdbc301c4e885ef615660698b245d8cc738fc12874c63b11c8698b557bbe62759d386560289f60cb6400ea32b33aaffd7251ec2056dc49686526a75191520df5dae58dc33bb05cb4fc4f2012c90133c7880c6737773fdf096e6e6e79a2db1eba0e920687b0c1156e26a9c31fdcb2705e6614e522a83c779930b554aebbb9e29455aedb017c7000000b012306248d60e6026aa247fd833a07e49533d3e1b42b3e8101bee7dc59a497db5a87398d35dd1b61b9ba740957e37b5031bd6c3db2c1653d29a30683a011a63cefb317e5a8899a5dcae4a439fd0b62c09a4b3ab2e1b751e23cc34ae295a12450c0153cd2294addb8084d9ac0fb1bff779173d91d09a50c96487a7b091720ddb6c4caabbaabd02b8536f0a4e292968e8a9041ab61081bd2e06ea1c6820b9a262790aafdd22f46d92cfa52d27b28777e38600000168000000b0034be26da65e82af5bfa0535efd16d703f75ac653f86fa96baacdff5923cbdb4c6f6eebfbccfbbe408d585c5ea4f4bf04c02a003852aa858573513f81410f59837684dbc51e2daf908cb38c17c4a03a7476fe6711412b004af9b7c375480f2e4d0b1f142ed5af848e671d81544714d1e0f924b152071f0655c9889e56e303f16250eda603542a39f8d1f59e02117067d1f71511291414d207b7c40bac5ca2f2356f7defd4c50df482b63e2771a092426000000b024d076d6b35becef6aeaac4796b6d828843e59a310ad056a2566a1d26d27545d62c5a0c53a1cc2e037785b750a55268353abb67bc8d57526b7c91d408c9ed259d5129f07a5cb95364fb9e49c96001125fb4511965f7365bb065205465c15038497ef9fa2b98fa3cd8ab4d0f3143e372c14553cc11b1d75370cd5cfa1412cb75a0808032532c0378d85d07da33b632a2d2e7af9f5916d18630a8bc7aa2f925054d9e82800ab76834e57640ba930cb601000000168000000b023e1598a7721a961babb637e6524e59c33dea50387d785c78d3a575f72282866862c53afbc8f81e28b259f3bfc702a4f655cd1deec2114f42f7ed62bae580f4f4ff947ea7e3df1d45e288507acc76263577b175ca599e42a0940e87f38e9ec2322a85fd228375de88d1240815ecd003f11f01ebf31d356d2087be76737dd91852213ef00e5e2de4dc33e8bd912dd1848156181cdd75180ea8ff80bd8657bfbc829f2eee0278f6ef2931586eb6622f97d000000b000a75d6c4caca13042d7d0ffe135e4b1d6694e40c343235b21f813ade0219fb1e18fc68da3bbfcceb1fa3e4538754b804d2d86dfcf8c4566186055bde80af3793c09fe903c6760f81634f5987572cc784cc4345293496550ab0a3b64ee198ef350dcacb5112ca8dce46dd9d10d510dbe2af8827958ca9126e4c66d331bf9a6694f44795135104ce3ecb869f9d9ae1ea328905390096410dd5523f9db4ded91ade15421264b091f5de5d161ff3947d35500000168000000b01dc49d9e0cc96ebd3b7138c1f03fddfc9e79427a43e01d30a54054e8ed9d50e425dc24b6ba71b47b6a0fc1e2b827273654dac3d95e2737140e0cc1e34ea9beb033470f48a2e6f5cea6ce0545f90015583ed5fce276d318bf4847a4dc7dfa937e5910d0754b3fc67c0d15c499c848d486098c20c8a7b68081e17bda40d7c100675f553acce59576c5914c5906a34519a215a9b9e8ab78bc3ba9b6a61120d02a312c3f5c1800c29531c296cf91ac3e37d5000000b01de09df9918b9f2d53801b6b661a0e4cf09d4dc5605aff95448034ea0c43181261b7e2c8747ab7ee1b39cea292d57932a1d588fdeca9d1cb5776c84ce8044319c81621bf754330ecfd22a695d433cbecdbf1530913624f2759ec668ff0b3c15d9619517c3e3dcc896c4c9e0506b61b821a5809bde006f8d07f72ca9f652723b52e0e66bae547c47ec95a6fc4d6b202441287e536ebcac2d85a0f9ce5e3b68964d78600d5d6ed81422e202ed8df499084003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b006768029cd28a50360cf8ccfb521f8df2980522b5409cc07f57bae4c0e7f07c302a82a4981a98c94be93fe056a53d5d1b719447890c7a2e9786f16f70a31b8538fa9f6970d6e83893df80db3beb681103594ef187e233f2c6659194a07ae4149bfa94aed447e576b09b02c8a0df188b1070cc4a1c7e8b7852b49034c52479c1ed243aae0bda94aa08bba7e03535892070a25d7b9481f8f07047b90cb47c6cddf183b6246d6083e2c4dd086d98f71c0ea000000b00bc536816bddd91ccf851bc5a3485a1b2e6649809ccf0f67e7bb599892c537bcd106d10f021040a5e2d2721f2d7eaac3ab8da6838e8cd9170b7a63e2f49f94b0371d6a48fb4a83a11d4b457574d20a5db86465330df0638a813e3352b67610bcd083a387735771bd44e180d7f88ffca2127e6fe313d9372ab7e8007ddb18e7a5c0b3ffe689dd97ba4c1354036f9fe7f91afdd57059798a982a0269ab132be95fd6946a361ac9f42bfaea9ca7bdc49222000000b028f82e3e673869ada81e80c781195b9b824fb203eacddbdb72a33b4720293257d6eeaae30d183598484afd0359c4990daa5311c7a688083b76775c8f1af7bf83b8d3947c2eb986280bddf8a2566013b58e8d9fd126dd8b8f9afed83201582b521038c136aa310c0d83549bc9c92378d820b4c02ab3d9a7049de3ca8d7a3c2c6d0ee09ca69f49992e2ca7846195414f3f00142e5c2251e0cd61ab065d184a425c6a7826240543aaca90e41f26116fdcb20000021c000000b0148649437822ef41d5c1d1141143b616a16bee2b984a1c5b7ebcb79ed08b6888fb4c7e6c4480715d5efe6d9fa6564263ffb6670150230c2eae30a77e0d3f20689f65107b3cc4ef25eca3d09f61e7b07e1c79fbaba39c793d7a06494457a5213b40374b7b474404418430cb9b06e2e4eb02045cd1a3b0c1b7726821ec9fd440d9029297fe40121caa929726bd408a6d960dc3f2bd085d79294d73b0df21ed844665d081a638f34a600c04194232ade860000000b0252dd989a044b10603610406932a6556f2b7e5d248e6a6bfe3d40b75d5d2955977c4531e5e00f843b8b1654167096420e4dab5cb3fcf7eb7472b73705802462038c1d28d285952ff95664393b36cf28067429ed6f8252041e0f99f20851b3a52434da96449835ff65453e045d1f305bc1869824c6ef26416666295dd9bfd6d725230a6dbd8217c4f5e091e55358aa3221a2b31114bea9c96bc17b2cc8c2636f3e7f316b2d9c73137ed2289329e02ff01000000b027ee0aeb5c02f81c5fc908b8407c5a117042e391a332b299abe65ddbb174fa6d525ce1dbc42bc34fe0735e3df3dc31b6dcf767fdf4f72caab6fc4380ac58185a0a2563b8dc7566ec02950d1b45d6383aabef90e9fedabb88385104ed1089e9b498540a9eeb767c16528ed74f266e599428ae50bfb856cbd15f9c5bf59c038e5fce0171537e8d76622e984be41af036280070a13507dff7d2d01c43e11e7b24de1126ecd66a9fe3669e51d153b7636f520000021c000000b02785d7d8ea54e2551312340d0cdcfaa79451b70f0d50940068049058017885756b3783578c62913420364037346a7e21101c5e73d47f4934e6777034ade7c8b99b0d6cd2430b8e729b300728191261bf847c458d41b73616f60c75c028127584fba181cce64797b0723774c9837761bf28736179809c73b1db47831bb976f611e7bde1f90306f64914eaf41257df861b20ee642537c720059997bab2e163ca445eb4bfaf46986c3f6b8d9d0ef733665a000000b00bddd4808dc88c60c27241a7049ebeedce2c0a3673fb61936ea6e1e2638c27f892820a49af91d7a8d51adfaaeb659a8d249cac1c4baff0a86decae44df49f2a447a89c8dcd96dea1abe6ed6bd21947f1a6218892eb87b1738cfea9354f13471f0001ba0612e6ec4a756e54b690bdf74c17ad49aa2f06d35a546531433bbf8dbc99f88ba3efefb40cbd2b25b3cbe3dfbd1d5188e64a5447a4001f8a2c3b3f6aae2efc082d294a1644326370099c201dd3000000b02526e383d609576b23a543bfa03401cbce4fdef48ad4600ec81932ed67b2eea7a928601f76ec22d9786964f389a1cd7fe34339175b3108d8a530f82f160a3324e71782597ae842bc8d101164f3c19545d76d6f5389a3cd37a3887be2139c6cb1cda6a7f45ee5d9f16673e82d41a934632932100d24dc1fcef0c10cc0a84f79e15abdab22074350b0913a0bbb289e84951f1308a34ee77629c0ebf2f301d788af0972d045ed3af37317ae9d0f7db6f09b0000021c000000b002488b885fd79f0ffb588a2882e7ff5c78ce11595a429e9c11ee1785c7c0e68d606d6984f3edb61c77c411319f81c5c10720d2a502ab4b10d5e3fc6c2e978af508cdb7a23ac5e03d3e9017484d5e6076cfeef00d61d69d7f1a00959c0ecb8df673cb0badde6c70b402065ecbb95adc0b03f80c391a57d4823c860b77b778c8645678f5df275e59056249e02f8913cb110fe764d8899f1ecd439a335d1b0fa26b2aaabb001cddf9471cbdebc6381ee00e000000b00e56eb7c3fdfdb656b279346152bf0997ec1f2618752ce25c0261d32785d6118af312217efd7aacafacc0abab5ca5fb5fd2e91223c1d44e198d6f9f921fe7dc4ec7c7beb64322a06132576e49a468c3eda011ca5f5ce2ea4d1a6809db9b11694f68d12071d4eb83dc8d843ce7f86c7aa2a14e423ca0ae451922a024bb239c050c99a9bf13cc0e5561ee0f359cea922b920dc30198fef34e847952850f6caa5ab1a218a1edbbcc0eff93a97a01b63d24e000000b0014d80949734369641f807402bcb2340abd10e5b0b157db1a1dd3173e94674b3f36154d76f760405405600cae6a3cc31ff1c8827336c7b1cfae4a3915c82dc857068aef86478ad627f5abe07f9ea11453f2ca805c5065384347bbe4067bd4028afe098065de8872f064efc88a6d5f2122558780f05e2300a37feec46eb6de234c53b33e178846039f9d91a01caa644b50735b3f1ce7f7ea0a9fec8ddfec6227ab97148cceda9c5515935d59272c312cb0000021c000000b01103475dac14bc9d3a7dfc5e2a04cf35703b1f609a792dd9723bb24644bcefa63fb1cdd56bbfa7ec717caca4b78c315708ecfa0ab548f652d13527338361ddd727b61d5aa8b3b13fff8251dd2b71d375cbba0afc92ce474d0d1664fa0da5212a1d1883e3165b97e1f564786e6a7693e11a97ead8c64ba2aea9a3f609de3181289608bb440edeb7635e5c0f2e5990bbbb1bac663ba1856fd2ca6f1cf07125e137fc310cbafcbd40cb82dcc8217a7ac9c2000000b013cb41bd0f6ff802d3cc83e3234640ef1d0016006cf0a15f05c62dc0f7ef33844ec287215d566400e09307ba827b40c452b07fdd0e195409b7daa2e32876e26ddbdf7030f274c85537f1a347f4ac8d7d4ef10b194bff3f9e9240cc996480749b4249ffee57eee1c6893953663ac2ce8c2dd9f502aaf953ae540adc5884520f2ace42ef608837aa4aa29a4009d861849b2a25f5cbc6a9f3b78b4bed1d0b116abbeb72a1ca0fea0d97c8a8aa07c8f1b872000000b006015ba442b8fa15aa0b5cb0a5beb539fc4858fee983c587bcb6d5499d52d77a149222d8e8e711ec04b1fcc3aced5fd7f0b096fd7055fd6b8c589cd000060a2d5398aa31857d61f62e0ce22da89e31eeee1d3d57cbe496559ebee6391b1cf301a0ea09dc1e46116df2f779b3bf5b80a2236d8415844da5a435248878b4a6bd545dee8217a6e8d038a14d41bb51ce8982290b12c23c31c856046d94d92fc96bead52270172ed40b131da45aa9e39c7e150000021c000000b0104d01dee7bd9cfe5109afc524bd87eb95d348484035d1e69eb7ec4a8964377ea407ac7c14ead237a1cf118300208a348320e319f4f2cd48aaeb9f8d896ccb0c02efcac6818d02e10781ca37f308983902fd38e6a84405601b03734d96c28bd7cb8ea430ffe36777a69f5fec14bdf1a82fe675d8206be460689eacc25812ea9c3756d7a43dd89b1b5c7c1b26b8fa39dd089c3dabfafd85aa08adec0e30d08888400f1cd7f41ceab010a98d5a02599242000000b01c9169d41291b77d9ce19b0a054252ab7b726e04fb1fa0146b66dbebaba9285b26298ad390015dbebbd50264804d2546b780a5f3b744c41094170c098a8f14452ad149686bb20ef3747ef0d0ff40bcd4d0c804766567bce6098605b2884520dc2ad7d1ba403acd215b4a3c598b5dbb810307eac876137461600886fcbde5fc8db360b96635544493d3c79f5bb44793861e16c65ac787c35c693bf099dfcafbad74d2a731e9f8368db921ad307813f0a3000000b02081d302b43ba7aef8d05a8678a6a1bef572d3e44cfbd640634d03cbbe896c6a48ff64898b2850d2299bf825f9ceb42dd65342607ef86a0602581cff36d8f9c2df7792a004744a147f4bc17dd6f69dcc4ccdcf6c3830162a71c136960c235a96332e7296b4672bca291ad7efe55ab81405bbbb2fe6151f6718d17bb5ec43a3eaf6291f0dc6e3271a785760ed511452b81b33f6de6e2a385b36f6e7a0724b402b781b688cb1d0f622aa54b68b119b57440000021c000000b00128255153a773decdbb15b57fe772fbadcdee1561dbf3e00a2a3b72db48a7a197ba156c9ec1780caadf081c2effb4641a78569dd5fcc0ce028ff3ffa805698f01006ea126d45c6aafeb331e63e98e1f80e21d04548d6fdc8315b81e716c14095b685b9956eb0edf3f6b88108f733eba26c512e57c6f4c5bc360d761a7154a890f06bea3525f00c4edecc158c5ec58b61642bb774fe11b07dda17b2cce8af4a461e7aecdae5d70503635a197b09d9692000000b00810d70ba15ec16aecb6ed9ee190c6a98a77e6cdacbcebdc0a480d8a0a98df1106b30b1d520afb283f7e3837218a27d51dbd139980a128b2bcb1e04a24bb8aa22971cefe5fa0a5527e409743b7cbee60ff196253610ec6c35390c028dbac265edaff6a7d4d3d024c59be940438ebcf74218cba59f8d93858b6dde962e2ea757bfb4581545736ca0cd21b777b302da110261114d4b2e35d17076ffca1ac3c76ddf60b8995e7eff212206e4a9867d95e60000000b0287065b83e3860e5b117e11c28351c6eb3f3e276f0a8fdaeefb06bf86fe1dbd982ec4c6565ea6fc66e5ee4a17fadcb5195d40840ca3979f52d496027d1421a396aea9e28d77fca403a42620fd50a0b05a754743ab14d0c3dd4d11edf49193e3681fd7739bb3234a108b9330ae92b7ee62a7316e2b446fa09b83c3d224cd6bcb450152c411d8b15c03538b6f5f8e444872e80a518f74762094cb7ba08d7f2c57e32eab20fedb23fdb92d5b20f483631cc0000021c000000b02751524b6986134323e8aae7875db506d4c103de95869ae6b413fdae6d59277805d86cc8b443d620bcb15c4a2539b3088e117d679a6ead6d1c047c16f6b706d07c58f96794ffa1aad2ee49d63b4f4f1e3c19ca0d7942220628375a761c34c4be4122b1beabdcfb4162813447b4abc7ff096372cb1d6d130ea442dfcb4fe44c01748f71a45c7b12bae87a96714161adc20055b691048fe3ff89193068bef83ff2c855b1a591eff0cb56acf3591d571d98000000b0102475f57c8183ab09e64112d29d17bd1fab79efc5a13175365d42a53b893cb315a7bc1fb54bdde71e9fd799bc160577dd1e2cb64f8f5062e8ff6f7c48f081f3e1445deae55a285a54471dfc889407cae7c13cfd2797a3d6cc7579f0e664fa5385d02b4966514564391bc17497c0166c2aaabcd83dd15efc4381a7ba1a9b06c179c5b4b1cac518b421e848d1d07849d5033ed8c466269979223dfe180ac1e77612c9fb6e844a2c8da65c6450e5050dff000000b0154cb52a287703dd50e2f0b71078a531d61f0b053df2fed25eae6da79ef187623eb02db474e383e573d4e27eb745375d38e47b57ec2cc09828b89ea7dbeacfed617e55df88b35ce5eaa062df2b1fb77b0abf7ae693d1d3029a96f397152edf3c0875d0ca5d08392be285791a995713182b4b8ee63d062144c3299942a98bc37945e528883d313d3a922b352f030d782d0ffb629cc648e0a8f7d3fc331fd89e4cdac71d5ece04d7b321c23111fb6167c400000fa400000168000000b0031e51040e467f4a1ae805f92eb4c9ce62c3f1f71fbca2427618d1521e909d0a6cab810e571646cfddd139f6cf59c2513433a19140dc1494c5c5750425a41c485fa7de41f036af9b6163f4d091395ce5111312fd576bd8a95a72603b67a0c4892aa9a063a2bcafb44a02edff52e361f103b787ca86f192857e0a47c9b60b6c53ff8a2673955cf8da160835923e477ec1111a6cbfa3fef6c8005c1df1bfd81a200551fd5c1e001aff6955b246885f9035000000b000d37f011516bd155e414e5ea3d04c1e100c6fcd186ebc04b2dc4dfa93e383673497530a0fa2324d2d8fea6fa1bcaa72e1facbc60ac4e33eaed540cf8de657635fa3a8055499d3e8e6c067331e4b96c9b69b27ede9a6d0d2faded42ba34ad44807dd80296b75bf10cd1952bea2dc44450895f5eb812d1692af24a9950ec2d4f4d2a94fb07b09c157799884dc4b0c582b29104d25638116290fa83b88d9d8ebb2704a861f41ea106047262b211403021700000168000000b02ef3b6363d7785d298d4b15604d1c2349c97a817d1ec4fe3e4baafbdfb5c34424bf1745d193807f7bc0b18a59c71efce7abbda0370a62db44b9ad973153932302a1a0d977fce2ad416722364d2443576d14e8d97e4c5e023f31d2cb88088dca8b90c8bfc619bcdd8d6a09b13e5d3ce2923f442e4ad210c0bd8f9e037e6347ac066b00c17010e39588cac509aebcc2448269bc399e5918ba5c4a40d8b8ef1620b1bf3259c4503833c5f26861fe79782ab000000b011b64c695112d84b8780ff647a6cb4f207e18b294ea9229d46dec33dfc3267d72d893301be63e85b2ef0fb4402931a6620750651b2e14763c1826830e15eabb89065f407d0082908e7f856df328f0194421b322945296863f511512153cbb1ccf12d0acf3ad503e4c5a007c32e35a3b71825d7070278aa7b0593da51a157c79911b3d5a15772bb27e01868d2b7645c6b05a7d2a6590e3a9baf20c4e33d1d489af15f589749f7823576697ad95d1e55a300000168000000b02c296cb94be9a3a6f22371026d20cbb69556c8e488dbd37ee4dfc8f5b3af7af4eec4389c8bfea29ea3417898d9a4e0578c5b0764bee3f8fdb12b621dfed96002d716be45895b660ef003bdd7a4d52ec88e0205032f3369b72c3d1cb514bc31fb4b457a920222b83f3dc892cfa7605f730ebb6ae7f653cd364521124170fb77156982090dcea17a54180bca30f4e24174195c93b07c210706d1b896028d49dd367e4569fe0ba86f44432c7e814ffcd0c7000000b000461ad05306aeb444ad6e1fdada2057a67d2204ee19ee5a2270e8e66c26ed95a9ae80245f31da836117c20f04dec8faf1bed2063205fe44de621a4d2936ab6071f4257d59f46348e4f02169ab202942b90923fb8c6447ff4ee66d29e2a2d0a22f5333eddf287ea8dd80a20167d25fb82697153732013ac2ccd907c99038546f38cb6fab1a29beea6c909492f4bfbd482f7d9d7d9607a62a30ff2980d39b18dcb3e1cb6472f5357e54fc290ee245e60600000168000000b01de6c6cee479a4c5bc6229f411a291c94940a941d27e7e6b9cd442568037058add80918bcff711ed6728e37c90ac55ae87085abdd40bbc3085f23d852d8015d6d2d7a72117cc62acc5153e0d67427567ffefb19abfe17f99fc6e82c4964798883761b43103cf0f9b4803a7f3e903210b2f9f20f705d6a44b0fccf858f1cac066735bcb3ad3252b29fc70bf22db14f9f10581b774791c5d78325bc5fd40ddee3dd518306191706d2f7523de259f4d5c34000000b00b8ce68f93a532aad8809c99d3967299b84d391f365ef4028cd52d594de946f8aca5313082e9d8848e59d247683da8f0df1f53dab53fdbc512d6ae9fdf0c14c34fde79087518ba3453bc6fb5e96fca87a2f8dbb6ea31d805fce3662fa34a15ded99c0ede2f544ac730f2021ab7db4ae508ec844545d16ed99b1dd5837d3ac9f988aef852accafc1c544b56e768f7e5fa130d6bdd8d406be2c37e7e36d98c0b998fabef45b837041764ec32a059cf488d00000168000000b0048564af9b9683bcf79c6d9c1855df2c6bc1850f8dc974310425db324db55a15ac9199387c02a08325e4521d92b2b0165196b00ef00a6a5b90c2455c081e2bfcf5ad4b5282629a405943c44a546e77571e0a5894b44d8267890c9a9c23d6291df2efbf0afd62b317d2c7d99e3da010d30f94f870e0774b74e2bd522ee81789c611bb9bfe9dd039904449e9631066789f1d2d7fe021d8faebf6d479e43569c854815a8daa61c9d22473bdb76a4cfe27e6000000b0261ce530c644903d323c8795ab0bca1ba312df7f0d3541235c220cbf30a29b51067727243f824a65b39112f4f1de8deffdde10c1c747b7e50281fb01f9e9dc7c739cdd4be8241f85e4dd3ff49b0e43552a5b78e740f529700b0cb39d9a6d203b2611794bd65c3b70855eaa32ae7cedd904a50053de6f5d15248e47d653e5d585d9cbb6895865c5e1810b25c48ba6bd7d06f85df401e323b1569185c76c0d6806b0d0f707a710a8928f0f8d082596157500000168000000b0093672f0cd0ae7a0ab38e9c60c6fac81a7a19e316415391b4f1e6adb563e577e48810e1aba5703256ab5149209293cc30012cee0a0d5253f883c223a262f1c2a9467319267bc476467ba04c97a4e863986c69a87bd8a8e1df5462f821a6a0e528713765a76b0dac4321e9eacc5d29d1f02319f5796b4110bf6a9d13d20307976e58fcab3184fd735af270bf1196bcc5f1665366383be120f6920c39d040c2b29b85d7d4989b5723bc6a2eaa1a5104f13000000b0144042e194f69cadf6b69dc8520c58edef89490b7cb92fde63e641aace529043ec4d57abe9a179f21d1fedc0f807c22f0a3ee979fc6319832015b594f19259c37d9f969a4cee3129b4b3a41e2b07c4456fdf2d1ed11b984f76fdda1f1b829bf1f06e1289d88f73e9e5463d935c4e7d160b3e32e661e628138cb03c8acb09977bf5471d6b967088d88bf612276ae2eed60f4910d04866537863a422d51409512794d5b49fb8e48d17c5e3d04188fd7aaf00000168000000b01de2c867ed5b8402ef91b3dfa29eeecb7b7a18fb146c950d3999a00c5550e12a310ee7d2afe72d629965c4eb233ebb2a75e1afad431799f920e2ad94e56f8bd175802bd6d97eaa7b41a447f00c7495bef02ba6168c055135258fbb77fe02fba817da648084b4d76848d11e077763fc1a1ba63ddd52fcabbe3cb7fd8eefb638e371e02c1b380ba7a3e416589f79519b3603352890cc251fde1d1e83b914d2d6bc68e15534b3b505f69e126f14c5444056000000b01dfc760fb2ca5d4e09580a1b8b9654c9856554ae4bd41df035cfa952a0054c21a2c3062eaff28d68e764eb44a0a3c1476975d9f20ccbd8bc17644fd5e585164a6005b2f238c51f8bc668a100a4663dec1243703aa15e4dc747d0fcb0737846f88bc5d020ae6bf0636812feee7e49beeb0dcc9192cb081b5fc268a842d37cb489aedf6d1f20423568f5b94f084f3a607a163981cc33e8513f61c5b1c78b65611b9047a9646c4dd12e79a709a9428db01b00000168000000b020d955d8ec78a29a73f7cb029ce63e2cf639ca0138de833055bd2f719e620969219efd20c90a39ef13338674ea461aca8dc6d9c9ba106645d84498ff9892379422616b807e6a97709b1fc8e57e7ac128be464296fa5a75228ce603575349a4aea5a389261362bb8941c5407ccb12a8c325357865f7bb9f6f14d62b8ae7fe130051ae3d20be185e308ea3550a20f86af80841567a67338501828267eaeaee93bbc4e112e684a4b1bdb2eb56ca78695b90000000b0049b8080c60e519e16c560eda5b49deec10fdbe4763c4dd51304dc6cc3f08e65159346fd753ce35e1386553d0f4e58e6ff1572ed1bf41d24380799ad13c8b673bb30010ccec4dd95af93762753a567cf145d6aa539eaa2045870789f455bfa5b5d48a21ffb412a67d67730aeb0c4eae11edb25c2b3146a4578fe066576a0e7a5fe9761144bbe4b98d87cc5094ab25e931c2f50e46dc5b96095c93e5647b70034d9cc980a60174ba147eade7e57fbd48500000168000000b02ad88e27219ea83385ebc8d7b22e12a56447fd8235f6e3d2e52cc5fc0695584bcb9903d92702aece9d3c581a06824bea6e3d2250226c071af5b1d04588196954046ad585b63ddf3cd5d32af42409e4d49c9a9e4ee85f108ffb213d951fdcf78aa825d1234d112bbf52d10c4eea12bd431b1d1362799786be967e589fba49951ceb39dd3e5760c1aba5f8458f3c7962a80ab09a584b5d29af6632a9b6b2a8f85e4971996b31870e136751e0c6b1919463000000b02f0eaa976e9f8c1a5ef60c9846232280a167f3fc424d85587de9dd5d266e4558493d7d357b8be022d12bf8a56d7312377481bc43182795ab1f82dcd7179baaca82a59b8eac8f7c79f38275f80f0a5b7e7485e63e54302628f12bee1b29d2380de0a6422442964fd3c99e46da6df0108a14b9a9c89266d34636af74412946a5b95f7ad54d796b90c84963b16ed9be4f3810af5d840706745ec647f38def4ef48c834db0bfe0a9afe0f35b4f8c3a87a46b00000168000000b026e0ca1bad90e017448c6f0e3ea2b9e64f6efbf840ee98f289ae0a4af8f6339a84b34eadd8bb407a4fb93c1a02e55902fe3304397fafdf94b950f35752222f5895cab678069be51ea3611fdde9c423028082e0b18edd719f7bf9fab7debef8c9e0800dfee2c4eed127c44a26f3131f2b0228fee1d3b47be325ceb5685dd6c8a06b13b320dcc87da59a59fb0f41506bc00a0c2f987f047a97e6ebc28fabb3abe568d9bd2ecd16c2a71931ab9ced8c9791000000b023fdac07533eec9cc355d41ec2fc21bd97298b955bbdac636f77ddd02b06e42819db25b2f8a85638676397fdee1bc370f1122986a262002db4ff1b78fcc6f07641137aa5213a6fb8437a7bc72172353ef3e50baf84885cfb4bb936a8b245305ed4e68c3295c4f7eb2917107ca661ec9928f027451c9eff1e20666522e963272c4f282f06fc24ece3f1edbda471194a4802d661d25fbe545c8e0e6308bd28256c7d3d333535639803c84347288920a9f400000168000000b001fc05e0024a65a6044e37c3e9806d23958f6d2cde17940dae129d6c279ba70686fcdcc5b17b5e338a1cb39ca5d2342f4de7ec6abc68d0aeafd53a8dc022fa671ba2a6bc1dd07a34d6d0ba037c66030ac608f15ccf2e1e09b602994f407abcfbf167539c952cdee3dedeb33dc791bcfe2684a2ac603108364063286e54e4c00c9fb5426b0b7fe4a7ca3b30555218b8f22f6994ed23bb93925e8036e2e4d60626246011f1dbe620dff6b1fb14ef583cef000000b01078effac36e0d27de210803d05e546be35fdbfbfb837ede87ac4378b5ebc54b0f3d6edf21009d811f39bfa954c1aabe0f56a9fda5cc07fb6d5df35d9e6d437fc013822e7de1c9d99ecf3ff25e926da0c6db680ef2f4d908d798d907c6b9031ab638f6907c2db2af8cfae9c340bde76b19c2326b1caa1d80f1bf1c94d20cba4eb4c34c5a186dcd63cdd864b2a723bf6919e368ea805867db024332660eff999d6e0595be6d89d706b52a6f65af91040b00380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b01be9ee74711cbc8664fe2fa9646d8793ac0f09512cdfdb4e134b02ca3d36f772b88903d1790543edf47c924f2e882c4192c9b0ea3a3e380bc0ccb23d008cd997f417736f4c9c42b1faf076d011801a54c3123f1bfab79753703ca271571f1ccf8b5641aff77512b2078c949fb29ed91126e76ba568f7a6af5012665b5fb4a5fa5bbc8b5024a5686a3bfae47752c1eeed12092ba9ceb697fc5b4e1b03dddc753cdbcf1b0455589d510bc8f3516f259a24000000b010e9c632bc127830dbf7eb07b4910ff4b42514724bd1493b2dff3ee4758bea9739cb21b08edd660a843ff971b855359081b7843f93c114a3a0c1f7b6967870702ed3f112fc4d0df79264603b5af87158777262fe33a0b6d3913740f86d2cd8f07acdfffda470388d881396d37ece182c2a8b1758b364804dfe674f823fb8d9c72c6b089d067f02dda109bd2f7c0815f708c5a8d573a06d2d25eee134769e10fa6a35716995e0c3350113832bb2b6ea8a000000b00927659b2928c6708a05b10f8f8632a82b34c30492e50af062c642af89cb195df9775b4d76818f7c347f3ef43ddd0c3b0290f2c6e87822e235c625770d81d920b4629125e24bc9b609e84993cc67e0c3b13ad61e73cc6c3aa9402eb3d4a8c31b34c1fcfe77acfd0dc9ab6008ee9d811b1f622929c6c941ef78e18f4c7a76cf3f429d0b2e100f1bb6800ed0c05d6950ca2b65a96696e480a03c816c971d4abfd077861dbbcfe4883d17767ab62ad2cdab0000021c000000b016d94b2b10e6a6441ae1fdd147ada37a7c00a7d4e81bb9b94adf5b5b851db1d3beebbfe8d19b84836f147d09445c11b5ef209063ef0ae740ea07c8985fd74970d57ff66cd84a77a83c7a07380ce3544e998f0485cd8b64d6500c9b22954ea913008d5b5ba826b4133cb6a3d14c91177b015eeb9a39a50c4648aecc8607f8f3ca9aee33be67adb7acda005bc794efd51f19c01a6f3372344dbe0ae658dfcaccafd59f691bf01727efea74f0b5772ed10b000000b01f3490f18947b0d23476bf3221d5d32e9421e326652b94b52f2881ec19cf64d94fcb7cd9aac95f84d290aacd722dce577c1a82f4e4b78bfdbb299a0195032f0cb5b3526b33a4e4f7371db6c3fd6f09a132566ca10d13da1f43d58cf7a248ed087f226e6e75da69883e1824fba2d1b5f8090e2d653ef4ed3eb820a81e6b3f13b47180502529c61a9324b80cea0bf7e0cc20695729200fbda732a86ccff0c0aabd36b7e9124b651732ec729cd20c053bbb000000b02723b78f598dd1863dbc106e2f0adc93864ba7cb0f04a181e41f5aec7fe944399ff699962ca81e72004f9a802446155e867dfb4817349aa35a9e9578f8f68987020ea1d1aeb0238f7881ba228a9ee54d3dce5d22734bb797d4707298a5210cea778cccefb066a8f42a7474dc7aaa88b8072e127e5d0e99248b095f23ed6c8c74119745a1d6549dd8940a3e2f3145753429046357e74512dcdcfa0dc28add87a55ec72e79596d8a90018638d59f53a1f80000021c000000b00879c17f276d9e118b9348022b7cfb305580a11666de198f93328141055e77020032622c7033cdf19e5c761f13d15b924f5e87c605630adef973e3564e998c5651dce0ef9b8372ba6d0da9f03d244e701978ed40b725d5cc705e8593574f4be51c4f05454b9a28a9ee0dc0f82dad291b01451f770c999acd74b9727133ef5012e6a4e86e5cf26af3c4c477c09ea2ee7922bbf3c952ec21228d7bfd98b0bc1fafe5884e43424cb23d311bb6dcafcd61ee000000b01baa734e6062e7d1e21295d03b5eaa9076e8dc6551caf50a8b78b637f4a7b6dcaf2ba038943ba42ac26311c35f863cb8087d1c1685deedd050f52bacf127a8ef8d8bb4ed57a874dae95d0a9f40de23082f02c17209289273817fa4ab50eeb7249af0cccbd8c21a74bb9a9f3bcb6c35d40982c26e826c267d296bf9328f80a1ad26f311c8b6a4e4ee8efc44e8249a17fa1793a78ff416cb65336dde8920e654f6bb7209e0b9dbb2b058b23a2af899d63d000000b00e6615111ed0ae1d1168681c930d571523f4d9b8931e9ee43cb1edcc358f4a04dfecad5d0d0fc7827a86ff8f915a2c46e88f8311fc6c3eb200a17f995bb21c42511ce1bc76c1179a9698dca4afbaad16f206c9b5cc002b1442e6167b9948e875a973d4914bb7554222542e53fd1faa58200fc9927bd6ebee7bde7f1687e1ce38126e8c1219f345df10b02a7ac1e7efc319f3c4469a52f3f798e801aaaa489cc3cb60bbd1c3d139e22c4e1aecdddc770e0000021c000000b02bb4d8744ce65ea29894217a92bf72ebe65f295ecbc55975790cfcb1a951ddc201b25bc6c0a261a49f8767883eb29ebf75e8cbc27c440fca5b416d42505f2ada4c38bdd3f21a0ab56b97af43fd3cf6d8f9447299be52c34240dd88608e5dd25db25d16d193278e41351e5b5eabf5ba6e193b06a4d43ea23564acac6af61403ac62de6335d5efdc8358a277042c93ba8016b20016c565340fb0053a94f0659268f089ca6f2c7fad381f7cf2c7a4bd0109000000b01874d6efc4689b0bbcc45814296600a909df900446d667973c2654af7097f8b6b0dd5c0e209422d716a4072e4acdc076983aa092c93d87bb986a120d5c4dbcc91fb374466793283eafdfc9e14cfc0daf761ec998422aa001028e1b9fb77f6eb6ca9f1ca21d61534cf1f96ca10c1248a413892347a284557f7fa6ad22c8aa98796a0f0e0b8d0fb8976ea3cc4fa1624915071b18d00dc6f200c250f9a65970e6614b3abe783aae20a647593cbc7622aa86000000b017555f710bb9716acf116bd7e60e97512672ba4bc3aad5033c42e5932c19750b63dc92c58c6c4129df2208f493e89deaf31fec8c88582b8e284e4c499ae1c1cbf93a3646751e952cf1f8fb35e7b7d2ff68b573a51e76f9c3500975648c65f62894125e9f7f663f4d278b2298a3a35ddb205b834e674a6be1b9d19a5bbc60df24193103f50fa63b1b98680664a9dceaa022c0a6bfa34e1b85a461233fa3498cbdf5d90f1740c295c4674d62fd31fdedbc0000021c000000b01a2545dfbc08985a34551c39cdafc966ff3a9a83b00bcb1e2ef623094240038ec541713aaebc905306a46898bd242b833c24c9884733876f571bfb8a553e4d2a3df0a9d50188e7eb1ef760df225df4efe45f5a96cc1d444dcab0fbf44a02f01c24d53bd85d5244b21e0790bee1fade342a846fd25a29edd1c22614fad59e123dea5fb465df12325594a4effa60f76e7e0823d8c7c952291b2725c9a10cbed135491df31fe7c1afb580ecc69f838d83eb000000b010a5840b07b1fd0eede666331d3fee1da8cde03d2b8f175d454b04f1f512f6b25582c441adbe535fc180ddbcdecc7c5221c439338bc85bf1e80690b4672df52aa8c5b745892e1f7a399cf3fcbdb7b35d3757edbacf4399300d72d158c496bf7f9213cfa6888a10c677c1de61ca0fbfc90b66158f9523df35882d1c48e5d9f65b27cae3384187b3d999cf7be267b2d6ba107ca64d15ed3c66099042b46804fdbbeca6231499dc46a2b6ff0ff57799da87000000b01c4907bacfb5f922ee3021091ab1268e839900011c62dae6c81bc51f518bd8e63cfcbc044679e34b909541d7b2e52bacc56a240450568a942f913dcf5bf3d7228f535c870fddcbb3635cf650295b417479482e9b7a7df497aa736e4e9e4a1d24dbb43e901f2561c450a00adef8c539d316edc5e8dd701be7f238db391c88fe1cea84b5d972beec8dca0e3815a9d3974923272c4768eff108a10122bb79dd73c7516c6a20da1a1cf2f89c9bce4e2e9ed60000021c000000b01de52c8f6a5e772b50e34724a0d0270049a15f731d98a97c2c06379e378cac178407b79cda141e4cc5c9f5163b19a7062b9aa250bfff00ff9f770d56f823dd330640b0f19b444b695ccfa5d34770d7b245514c3a1cd980f6e4a533a3956d0c57d0b0a8d62afd9efd7709fbf26e7ddef62bac75f691b64020daf62fb83220a2e7069d1f6502964c73d76cdc4add81435708b07cdf574f8baaf5535c16eee82e37d4ec160df94018703f188afb7ef185a1000000b0190f710984c36ddb118a7dd4f69f4748700d07891cdd42c55f80ea72bd2a3cbca0a9b46645c9baeff5610850d1fcee3afcfaa443ac9251791c8c8abe07d17a4f15e7c1505cfd13f88522ed0a9caa09f8cb9e93d20edc997d77666595feda6941b6c5eaf8aaf40a83881af8e7c1447db128a92dfebe61cf11996cb84f178922fba90e8162d1c8dccef5867c253f5be26a1d5b298eddf91516983565823750f78e4fcbebff458ff5adacde04991f6c3206000000b0063892781f30a5d134ce7d27a6eff85d61a812fdcf9f93a90c93477f6ff78d01c1fdde9852e46c2e061cee4b1dfd659d406b77ab295e6662ee75f5ff918d616e2ee81d3799d784ec0d0c99f02f502b61f22a90bb9852cbe4b2b2da5c35c630616b67776d02346e2d27ac74813123f1d7230d8ba8b9b538b23904305afa44bf2fcd333663176897a8f7bc2546820d8fea1628c864ef2c87e9eb65b612f5fde15fd7cef2c7c564f59cc27fff6e08d6e75d0000021c000000b00522a1ffea8d4d586b99fbb50b86b2fc0c81fa203c5c9f9c9a579b36c0fd4edd831132683a3a190d4fc7c2b9b0d4d4fd42e14a706add1044ffaad24a308cd6523a9e74957baf4bffc51e0f15d818f85235461b7cc08db0c80f87d33e4c708e1f7cf5036503796d83899cc4d2893b2f8f1dd0949e43c3bd3a249cae750b845e6e470c6544eadc66eaee65533354b6c3862a46e2687f0b6c58214c629b31a9f60a22187aa012f6b502e94dd3b3df3741d0000000b0221f434f2a742c17dce208dd8e16943506cc690aac8e255ee4d883a2a3739cf8d1aecf92318e49834abd838007b22502fcf54f0cc0aec6b2eafa5f3195178c6e8114873bbf7dff6835143665b69f1cb49f40d7d0487fc94a258c39a13d66982c556de72b549171f492880ae9acdbefdc08ca30c5405ba9eb52d43c9d9132ce6385ecda93f6f6f03aef7fe1c0ce5583f50b161f78e18c3537db1b174d01737361723f5f0b6d8aab2880d0d9fa642c8f68000000b02d8a0c4bc3303e3a9eb28ae04dc9c9817e24b10782143460fa0436dbb232830a1b42d0d4d9546ce77bd4bb6e02018e01f56e265a0236a809732898861e2202277d587ae0c972b321755a67fed038393db9906e8a8fc17ecf8bd340c6abfeceda40751c0199dff02fa8fe395b1c5d4ecf05982074cc23680e9fd1b017dc6d88d8b47172b21bab59a5519fc90b49029eb9180cfa367763deaea438a28c22f33fb6babd7df4a37e9293c2159d2eba2c14bb0000021c000000b016f0ea9ad0a62355e9e96d2e8f8925fc898e88395faaf38bd2e8424d3c97bd4fb2bb17cf49c6f4235bb03a06f881f45eeffa91c33dfb0b3786664642d876e851c698c1ec38ce9379e4c5e3c585976a88971aceea1474e3faf373072ba452e123683ec81aca3b40c7496d850860c71e2918889194e8b425a445834908cdd559241270304c3bfd5e52f5feafb7855a741f02ea421277c0e84fac87f364d8b8ae0565a84ca466d0eda9f85e1c5915a3ea1f000000b029694f12b6952b5c4975a51c48f051468980bc37c3489604ebd5decd41b974ff329024b37d7477466e2f1c65127934f4b822885f8a7c4186934b5623adffc1c910aaed5dad96fc401d8608732aeed4f53208e008a98dfc363de8057bf064034cc104fffdc646d1bac4294a2263ffb5220b77d62e056b77e97541cb3470c95de7c3219a1580c85ca7f196151ef583a2c8050cb1f542ee531e98230ad6e5a9a67c26406e68767e962d564407536c4adce4000000b016cfbb94e797e3754043276549b88e3c364e4910771265b151935144a12e8d19eecf9fd7c255b72c30ae1143a8f65348ff99724af312f6f60f349bc95b70e683e4c21f6b35933d52a2a22fba32e472a6a3ece8e59d689df203cf63d5a0214586fecee41d615e61c670737c2256899afb0ebc95252a9cec16797d15622bf31053fd49160bbf618df9bccbb9ab5c4fec3610381e40ae1b8e4cad64406a8e5436bd9dfe665702fa30d86c39176fc18e407800000fa400000168000000b0227f82609a148c0cb9c3650652b0934cb246a4bd453361211dbd42989e9d6ac3f45f754dcc44a8e5a626a7eeaa49565198f9721f478988c5f9010a1de1f271c1d89ff283dbcbeca959e952cc66afea40e4b7e58333d33e718d6d2f267c1a6c0ce7dbb10e56377689ed20db7e95fbe89f24b0b89b60d63b29fedf21197307131425d25becf7cd18f11673bb7f179ec8ce0fce04732b1235e1daa483e6baca8dcc898aa9b29de7efb91eb962716cbdc8c2000000b015ace5d2c53b34b875cfdd2b9283e1fe1ee40d1d3c8ca64556698214ab43cd5be3bb45adedd496406112c1fdada36e0985ff023b5c6dda3a2dd6e6d3de53395ae02948e8e16c422e8004f1f0420cffa484badd7d027a0cd14b5eb31fc153abaa2378183f9505a23d029811696907a1b11216bcdfc706256a403f8ee3894f1ec1ea9f1e5018621b86555407da12a4f28e06475670ba2c2acbdfb8cb52a88a917780bb060e1a211625e9d8b2bf3d518b5200000168000000b019651c1fa7b7c30fa573ef9ba58d91d8fc9926539c37bca5958ec6758b4c346c1f3653df4cbcb47a8b4acc183e6f2d4fdfca761c876723d46f706d20a728f46166549b0244f8dd1ad69798ee23b055bca15f95d35a62c4577bc6649fbba6e30a6b71676a748c04ab5dd58f2fdf034be6275044fe7230a487b8d9c19ba7ecde2614c25bc4b50f0db2638400467c9790211a07c82d336305543f419070a9d3fe87b05ff9756e1d1bb72c3ab5c690d1e760000000b01258d27e86519b01496a076fb8cb0645fe36d408da480786dd0c44d0299b24c62acc7e57c90060316920fc3e4474d437fe7b7adb7a59d46444aa6002ef16c850bd1db53f32116bca9ff2417f85ce9d5c163194b0d94b09c0c0922f46a19c6cb2e24edd4b7b9914e0edcb6bce0023c2d427e778c7cdfb1eb96d091ba01da6a33c942be5828879ad11f44983152ae277241d6d369a534738c2190c9eb54bec2a0e34d24de3651addbc9429f5f4d015c29700000168000000b01dd6c5b16dfd53fce2b480b6c06afb675f6c298118354aab2eb35ab320774f55a5a87d6b4f344c2b71a03615b30f28ef7befcf2102d07a63579a2d1ea9aedb54657896ec68e5b4f0a1293ebdf83ac9a41d88f9e8289e5f28bd1ea3bb82d21d39662b9932d0b3ad3458919e21bcccfcda178a4ce1e120a1f2a591cd2e365ff5026456293aa8e91291373d4776ec1883ef09a29082151f301be4fdc8d133fbb022085772fb461565b50f4db29c7d677317000000b01ddf1ffaeee0bafcaf46c5fb4919df7a09c96e2fa03bf29aa4a3c03315aec34bad847b28f8f5da2603aa5470c4c46f8b1d441d6fffcf6644b66ab9725ad0c6b00302bd4a239455657b68702007dc50fef9b6b0e6851eca1ab09af077b05a3c3fce16d2a06455c95a6879a12e4ce8ba001f3139acb3d31f27545e428a646496ba68489385cd72a707231197552848f89809858f1756f41f1752a757bdc6bf55cd9947c93fc5edd704369eb8728b67aa6700000168000000b0023929e317e443b128946a596d0b374d481fc2132fad9ce4d36b92962f6f0fa5b49d596414802a73da4c44e4f00408f81cee5baf4288f4aba4074f7e7033e0aa58485b8bfe207c91e5aa32deae6dd9f6bbf8252d0086b2d7163d943c9d3b4f63e23291762e7bc0c11731f5d8a99aa36111484eda7daf4bea5b2babf2d30b85488ebfdb303041a93a3c51bfca887543731562e1e8ac237ea459666b20aef239e2bdf8fcf241094ebdbb8f749d3f9532c9000000b0239e835d9175b3431fcd2cfa7bc590f1af6234e39afcb6fd6aeacff67f2704fe501d7b6e24ae6fc13fdbfe93dbc421b38c8e76fb8da387668eceb002961008640a896f7b7aceb9420a4813c122e5c714bfefe0d9a0ac899ca8bd74d59d4a2cadf4807b3be3984a3052c4210cdbeb94a60c7ca65d04c29786a8bf45e030d243aa41affa5cbadc29a374ffc6e76658797310058726fd924c54a5348d805a939542099487d9e28561c53c260a4c3861793900000168000000b0052d50bd76d903b508eedc5c3e9f4a8bacdf37e467abb25ea693ea76456b3c8501f2fc365ec484d5a4959ad361380eda28389e00723b48225fcfabf2574eeceb08d8801ceb39e61ced5bb7cf049829b42612445bec63faeb14f1553b2f3e5834022f69facfb7dbd49ddccf5542d92711236c908891fe8aefdc2d6a82cc075941f1d7bd9d5910a5c34f43f3b62d1cc7410a4727b9b12c0c0fba40676d0c6ae731740b6f3142480e541ac284cd66b849ec000000b01e42cab3af45d9b56ea7c1450d92aa1591f406b43cd2c5cdfbb9c89de7c5d8cc001c8ef7a8ceb7975597c0de719196bfd43bd6ef1ee84a5867985a9e27032ba305d5a44bf2434c6d76790ca42bdcc1562d3d8e07dd98a3a4a09a578fdb028b044c58e87d39d0b9f12a941052f989a3f5142107672e7cfe337c0c40dce497d7f9a5e2792ee09404bc4b822ceca876a5f222daa21fa8dada50fefe4fd6bf59ac9ff4943892236814ace0a1fc59bcefafc900000168000000b008ce9f550d5fd79a1e25b3e13d59a81abd5471f46f0060ef992758388c6bea31ad83205ec03b14fb5c4d154104c8c5f2ee4126c0214c91e290a355f8845bba4c4e85d0fd8a5889f6d9d02d44722f4db7e3a53c9f62f24bcc2ff6d85d69b6f1f850e355b93febc8f072d51ea418103b0b018c8f64b1975e638fa34d614d071508af4edbc90fccb16dddbcc0b2a965db4b0e772df56ccf60a066464a49ea59ae9c57d9885eec2c92e5890ea382e8fd107b000000b004ebe27bd3b08267567506f9fe653f1b3f99574121e3faca2c6137f55680aa696801a7107a33758ee40e2868cae0f79fbb852a430b0e9957a702faeec0a37300b4fd5595348e5dc660b4b04bfa81d60c90a1c1d163fc526be9f88252217c03b1b465ed8b6a8d14674a78a1a1ddace2fd15aede962daaa3f11de9ceecc8887743602ffd592000eb7e6d777e312b521e6d2c60fdf1c6625422248fb63ea34f04a80711c255e79ccab59608b91844db7c2400000168000000b01b63984f2593871ddde5fa63a3653da8ed1ab03ab67c9f8e3774f6ed46bd7c8de7e2ec26c9a77c948a10aa142bd6d1f15168f18a172399b12559b8854182800a9fe1a03e586a0302268151b74149544219caf39ff82d65310259a2e2ae7bf1ba0d41cdb4a2f39794ed4496d5e0b210061d0f32afd5f0bca95ba7df2b814f9140917e729fbf1fa260421a853635c74c592680372386d29ee955adbe8b10a1da2dff963576f56c5c30e63782ab976da2b6000000b00a5a73e2110815153ad6006b6d9978b4f1f620b327a3a334c97804d999911146e0c73d3bce6bb87d2c30aebb7837b78d49ea685833bf62ad03eaba9d8b902e77ce62a5f272d03134fcf25ff723046b79a96e60e53bd466f0ee319910e57b1d839e2b0801de2736638f5dbbfc3ec65355298e7cda6f7cda85f850089ceb479980865f457ac1e8de1890ac5fc60b8ec4032b648cc0d60ffaa5dceb1dd921b4954a9188fef7772eab280063b8022b40352400000168000000b01ee6a528352471047c49d5da60928306f8ed54d7440946339bbe83f5b7e346a54590413f661475736a518b8b4029eb7dfbfee253f57b4b844aac45fdf118316726d1703628a2637a714a937de8caf442ddee045464531a43c5d8c818c5c09f7bf2e2124430ee889b15b587179fc3cd122dd538c6335c439dddb4b941ba117fa44183dc56ab0ce10dc6cc7efe2851243d08373354b27a5b647edb318d94e3f00147092274425247658ce21a974cd64fd5000000b01fbfddea2101b814a3b7cdaf38b9725926728c5a206ab5b1410f8c4b88e2168164b421dfa1c3179a5517a933b47e42fd4dd9b60a6983acebb84761bdacb65a9d5e35def835caebcbbaba29c301785106dfb16b10785b35692fc3ec77dccace0b0d7fdeecfb72fb3ac810a1f38ba971f31bfc6fe31fe43b57ffd9c47e747d2fc155d9792c9c1753841683696ef9e0f1ee10ef1c49232b7134a7218cb4efccf6ee779bae77f86e11fd653f6b82bd65e37600000168000000b023de561c41c6be0497a1836b9074016af2842649024670a203e8a8afcabba0f5cf9c32668fd6008f011be75b95459ab253b5b8a55cd8e7ffcf4cc37fdc71809997a26140cd90f816969b2892445702b3041ad7d3658c0f885f06ee774b601296176c63ed159ff10dd2d1f8dd4e76352b13ad5b8ea382e930cc78371f505fbb332231ae2d30b750d4482b39504950b23014e9b9ee2fa1abb8fa6034115dbe6ab8bb1655e14a0525a619173d39182c659f000000b014febe858a0a6909d1b496516b08a09c0db70848df7b8bf53efc9287af3876e7c88e5a933c576f68cf51528c66ea156029d349e6fa1945a3b7d7a38282c2ca47cad3e8ce719736382cdb8f753cb0bd4ebfac555a1937dbd5cf02f0a42eb5fd65d10e46b52486bf4340e26a002aa7eb8b06b275aa45a389ac2e133c290e0e1ac6e6280ae5090d0d0d532d21cbafb69fbf0bc6de0d2952df114b105a73d16fde3ddf301e7154dac378d56a55c3ef0f6aae00000168000000b001fc2b23c01235eaf8cddc433634cde6778ab69d60a9f1de3e209db61bb18b99548d34e713ff9d1fcaef006f333a4abe4c67a2f181418c0dd32713d79d69a2c6425f0cd4294d28484d6b5cc710118f9592b162d5180166129c06578ca398e628e4046de53cfb19f4a0a98312f391d7390e8de589059ebf85e2483e2f9d878bc4c1a0eadb5a3e43e023e00ff975f4926707834d4b5e555503d1edd5d20d99620fa93e8e549c17d048f126d23d025ecad8000000b00e40a46861964afc6ac69d065acf0fae494991f36bb7ca1c8c31ef9d794e7909dfa20f06b472ea1f6b71b06d7df833b12a604a3d1bb1860bdb27804eccd3c27ce1b07ef59800e392aefd25ea2812fc27f90c13e124c2eb95a47a641dac53c4defcae6f5adb02aaa74ade4e66dc0fe3522bf479c6f48d8dfe32eb1db032f7a0ca736601c584b44799c38a593c54f3b5b52cddc8c94cf25618e49c02d22b5d2f003345a3b9313267350b19719ae8e3217800000168000000b02363f910f550973739436ee40527cab175a9e9ade7a88ef4c906d819741098ff4942467a90966f01e1c13b926fd01968affec2f16571aad7012da9f59a73a3cfd65c7636e51b3386e75977ba4c94d68ebb862f66f32132731738fa1466c3e695dd4faf9188c901eff292ad63b577e9e00b978e265a8ebaa682f55e7f19000e51e2a83b05c3abcec9adfd1b17da8873da028fc9433647caec05586d96bb394ac0f8f68f4320bd002ddb9b7be9c7a9d749000000b01ecbb28b3780c1f688b40042d46fb615a854715b2f887930b53ecaeb18f38177ed126d7939b0238ff1fc060357bd581a402249a826d87e75cfae94b8dd7a12566eb2878bbab3dddd09bff5b0ea4b051a4714d96edadc76b4b2760a508b7ce4aa6f635df0ead61ed3ff946b060502f02b0de48fde66cb196c3e33f32573b751291a74cc947d879f2ca17381480a9603730b968c50f7e8b98dbd6539390d248e16f6714f2ae60b731706f322ef288d2a1e", + "txsEffectsHash": "0x008aa79a60dae1c619fb444fdd7ca7abf423f96d7bcd650a3282c5267d3a8faa", "decodedHeader": { "contentCommitment": { - "inHash": "0x2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a4", - "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", + "inHash": "0x00212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb891937", + "outHash": "0x00a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd", "txTreeHeight": 2, - "txsEffectsHash": "0xbe1ba269c87d75910b743b4192380a38882351d7acb5b6c0fda0c07622480d3f" + "txsEffectsHash": "0x008aa79a60dae1c619fb444fdd7ca7abf423f96d7bcd650a3282c5267d3a8faa" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1711012003, + "timestamp": 1711036016, "version": 1, - "coinbase": "0xa23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb6", - "feeRecipient": "0x09cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d" + "coinbase": "0x9ede22c45cae1d9aba3dc43ca9a4014868dd9416", + "feeRecipient": "0x1db11c308c86c9548e554e8ea4ab6a0e7c0715098a8e50d016c9a7d2cf3af8b0" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x1e8e3ba20d7896997abf13f5f7e5a423fff51aba54c85ec8bd0c7eb18004252a" + "root": "0x1ddfa79462a8e2beea5cca8199d5ce0f9b0412d561d4a35c8905b8e8b2beb7ca" }, "stateReference": { "l1ToL2MessageTree": { "nextAvailableLeafIndex": 32, - "root": "0x2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa" + "root": "0x2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d" }, "partialStateReference": { "noteHashTree": { @@ -77,7 +77,7 @@ } } }, - "header": "0x1e8e3ba20d7896997abf13f5f7e5a423fff51aba54c85ec8bd0c7eb18004252a000000020000000000000000000000000000000000000000000000000000000000000002be1ba269c87d75910b743b4192380a38882351d7acb5b6c0fda0c07622480d3f2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065fbf8a3a23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb609cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d", - "publicInputsHash": "0x1c4f4002c3ad1dcc15cc1f45b785143a4e0f88c6dc513bd96349395209d670a8" + "header": "0x1ddfa79462a8e2beea5cca8199d5ce0f9b0412d561d4a35c8905b8e8b2beb7ca000000020000000000000000000000000000000000000000000000000000000000000002008aa79a60dae1c619fb444fdd7ca7abf423f96d7bcd650a3282c5267d3a8faa00212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065fc56709ede22c45cae1d9aba3dc43ca9a4014868dd94161db11c308c86c9548e554e8ea4ab6a0e7c0715098a8e50d016c9a7d2cf3af8b0", + "publicInputsHash": "0x00c7f2d2d6b9addbb841799014778f84a8ddf77d35513a0bb2a22e417d3ed4b4" } } \ No newline at end of file diff --git a/l1-contracts/test/merkle/Naive.sol b/l1-contracts/test/merkle/Naive.sol index 6ab6c896a48..9d9fcbf84b2 100644 --- a/l1-contracts/test/merkle/Naive.sol +++ b/l1-contracts/test/merkle/Naive.sol @@ -2,6 +2,8 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; +import {Hash} from "../../src/core/libraries/Hash.sol"; + contract NaiveMerkle { uint256 public immutable DEPTH; uint256 public immutable SIZE; @@ -25,9 +27,9 @@ contract NaiveMerkle { for (uint256 i = 0; i < DEPTH; i++) { for (uint256 j = 0; j < size; j += 2) { if (i == 0) { - nodes[j / 2] = sha256(bytes.concat(leafs[j], leafs[j + 1])); + nodes[j / 2] = Hash.sha256ToField(bytes.concat(leafs[j], leafs[j + 1])); } else { - nodes[j / 2] = sha256(bytes.concat(nodes[j], nodes[j + 1])); + nodes[j / 2] = Hash.sha256ToField(bytes.concat(nodes[j], nodes[j + 1])); } } size /= 2; @@ -52,9 +54,9 @@ contract NaiveMerkle { for (uint256 j = 0; j < size; j += 2) { if (i == 0) { - nodes[j / 2] = sha256(bytes.concat(leafs[j], leafs[j + 1])); + nodes[j / 2] = Hash.sha256ToField(bytes.concat(leafs[j], leafs[j + 1])); } else { - nodes[j / 2] = sha256(bytes.concat(nodes[j], nodes[j + 1])); + nodes[j / 2] = Hash.sha256ToField(bytes.concat(nodes[j], nodes[j + 1])); } } diff --git a/l1-contracts/test/merkle/Naive.t.sol b/l1-contracts/test/merkle/Naive.t.sol index 7b6dee2130e..d3f056781ec 100644 --- a/l1-contracts/test/merkle/Naive.t.sol +++ b/l1-contracts/test/merkle/Naive.t.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.18; import {Test} from "forge-std/Test.sol"; +import {Hash} from "../../src/core/libraries/Hash.sol"; import {NaiveMerkle} from "./Naive.sol"; contract NaiveTest is Test { @@ -28,11 +29,11 @@ contract NaiveTest is Test { */ bytes32[3] memory expectedPath = [ bytes32(abi.encode(2)), - sha256(bytes.concat(bytes32(abi.encode(3)), bytes32(abi.encode(4)))), - sha256( + Hash.sha256ToField(bytes.concat(bytes32(abi.encode(3)), bytes32(abi.encode(4)))), + Hash.sha256ToField( bytes.concat( - sha256(bytes.concat(bytes32(abi.encode(5)), bytes32(abi.encode(6)))), - sha256(bytes.concat(bytes32(abi.encode(7)), bytes32(abi.encode(8)))) + Hash.sha256ToField(bytes.concat(bytes32(abi.encode(5)), bytes32(abi.encode(6)))), + Hash.sha256ToField(bytes.concat(bytes32(abi.encode(7)), bytes32(abi.encode(8)))) ) ) ]; @@ -64,11 +65,11 @@ contract NaiveTest is Test { */ bytes32[3] memory expectedPath = [ bytes32(abi.encode(7)), - sha256(bytes.concat(bytes32(abi.encode(5)), bytes32(abi.encode(6)))), - sha256( + Hash.sha256ToField(bytes.concat(bytes32(abi.encode(5)), bytes32(abi.encode(6)))), + Hash.sha256ToField( bytes.concat( - sha256(bytes.concat(bytes32(abi.encode(1)), bytes32(abi.encode(2)))), - sha256(bytes.concat(bytes32(abi.encode(3)), bytes32(abi.encode(4)))) + Hash.sha256ToField(bytes.concat(bytes32(abi.encode(1)), bytes32(abi.encode(2)))), + Hash.sha256ToField(bytes.concat(bytes32(abi.encode(3)), bytes32(abi.encode(4)))) ) ) ]; 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 0ddb8aebb08..a8d85a67c85 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -39,7 +39,7 @@ 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_preimages_length: Field, diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index 1bbede44c45..01751c1d3b6 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -24,7 +24,7 @@ unconstrained pub fn emit_encrypted_log( note_type_id, encryption_pub_key, preimage - ), 0 + ) ] } @@ -41,5 +41,5 @@ unconstrained pub fn emit_unencrypted_log( message: T ) -> [Field; NUM_FIELDS_PER_SHA256] { // https://github.com/AztecProtocol/aztec-packages/issues/885 - [emit_unencrypted_log_oracle(contract_address, event_selector, message), 0] + [emit_unencrypted_log_oracle(contract_address, event_selector, message)] } diff --git a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/base/base_parity_inputs.nr b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/base/base_parity_inputs.nr index 13bb7b0712c..52a5f4088f1 100644 --- a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/base/base_parity_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/base/base_parity_inputs.nr @@ -3,7 +3,7 @@ use crate::{ utils::sha256_merkle_tree::Sha256MerkleTree, }; use dep::types::{ - constants::{NUM_FIELDS_PER_SHA256, NUM_MSGS_PER_BASE_PARITY}, + constants::NUM_MSGS_PER_BASE_PARITY, merkle_tree::MerkleTree, mocked::AggregationObject, utils::uint256::U256, @@ -15,19 +15,8 @@ struct BaseParityInputs { impl BaseParityInputs { pub fn base_parity_circuit(self) -> ParityPublicInputs { - // TODO: nuke this hack once we truncate the sha256 in the frontier tree - let mut converted_msgs = [[0; NUM_FIELDS_PER_SHA256]; NUM_MSGS_PER_BASE_PARITY]; - for i in 0..NUM_MSGS_PER_BASE_PARITY { - let bytes = self.msgs[i].to_be_bytes(32); - let mut result = [0; 32]; - for i in 0..32 { - result[i] = bytes[i]; - } - let msg_as_u256 = U256::from_bytes32(result); - converted_msgs[i] = msg_as_u256.to_u128_limbs(); - } - let sha_tree = Sha256MerkleTree::new(converted_msgs); + let sha_tree = Sha256MerkleTree::new(self.msgs); let pedersen_tree = MerkleTree::new(self.msgs); ParityPublicInputs { @@ -40,21 +29,19 @@ impl BaseParityInputs { #[test] fn test_sha_root_matches_frontier_tree() { + // 31 byte msgs let msgs = [ - 0x151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d78393537039, - 0x14c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e, - 0x1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a1, - 0x2806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e0 + 0x151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d783935370, + 0x14c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f, + 0x1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8, + 0x2806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1 ]; let base_parity_inputs = BaseParityInputs { msgs }; let public_inputs = base_parity_inputs.base_parity_circuit(); - // 0xb3a3fc1968999f2c2d798b900bdf0de41311be2a4d20496a7e792a521fc8abac converted to 2 fields - let expected_sha_root = [ - 0x00000000000000000000000000000000b3a3fc1968999f2c2d798b900bdf0de4, - 0x000000000000000000000000000000001311be2a4d20496a7e792a521fc8abac - ]; + // 31 byte truncated root hash + let expected_sha_root = 0xfc986d54a5e0af4f6e0d49399b9806c2b225e6c652fa5a831ecf6c6c29719d; assert(public_inputs.sha_root == expected_sha_root, "sha root does not match"); } \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/parity_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/parity_public_inputs.nr index 4a5587b9d13..9f9a5e08666 100644 --- a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/parity_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/parity_public_inputs.nr @@ -1,10 +1,9 @@ use dep::types::{ - constants::NUM_FIELDS_PER_SHA256, mocked::AggregationObject, }; struct ParityPublicInputs { aggregation_object: AggregationObject, - sha_root: [Field; NUM_FIELDS_PER_SHA256], + sha_root: Field, converted_root: Field, } diff --git a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr index 7f230332d94..10d99aa656e 100644 --- a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/root/root_parity_inputs.nr @@ -1,5 +1,4 @@ use dep::types::{ - constants::NUM_FIELDS_PER_SHA256, merkle_tree::MerkleTree, mocked::AggregationObject, }; @@ -19,7 +18,7 @@ impl RootParityInputs { pub fn root_parity_circuit(self) -> ParityPublicInputs { // TODO: verify proofs of inputs.children - let mut sha_roots = [[0; NUM_FIELDS_PER_SHA256]; NUM_BASE_PARITY_PER_ROOT_PARITY]; + let mut sha_roots = [0; NUM_BASE_PARITY_PER_ROOT_PARITY]; let mut converted_roots = [0; NUM_BASE_PARITY_PER_ROOT_PARITY]; for i in 0..NUM_BASE_PARITY_PER_ROOT_PARITY { sha_roots[i] = self.children[i].public_inputs.sha_root; @@ -49,11 +48,12 @@ mod tests { #[test] fn test_sha_root_matches_frontier_tree() { + // 31 byte test SHA roots let children_sha_roots = [ - [0x00000000000000000000000000000000b3a3fc1968999f2c2d798b900bdf0de4, 0x000000000000000000000000000000001311be2a4d20496a7e792a521fc8abac], - [0x0000000000000000000000000000000043f78e0ebc9633ce336a8c086064d898, 0x00000000000000000000000000000000c32fb5d7d6011f5427459c0b8d14e91f], - [0x00000000000000000000000000000000024259b6404280addcc9319bc5a32c9a, 0x000000000000000000000000000000005d56af5c93b2f941fa326064fbe9636c], - [0x0000000000000000000000000000000053042d820859d80c474d4694e03778f8, 0x00000000000000000000000000000000dc0ac88fc1c3a97b4369c1096e904ae7], + 0xb3a3fc1968999f2c2d798b900bdf0de41311be2a4d20496a7e792a521fc8ab, + 0x43f78e0ebc9633ce336a8c086064d898c32fb5d7d6011f5427459c0b8d14e9, + 0x024259b6404280addcc9319bc5a32c9a5d56af5c93b2f941fa326064fbe963, + 0x53042d820859d80c474d4694e03778f8dc0ac88fc1c3a97b4369c1096e904a, ]; let children = [ @@ -67,11 +67,8 @@ mod tests { let public_inputs = root_parity_inputs.root_parity_circuit(); - // 8e7d8bf0ef7ebd1607cc7ff9f2fbacf4574ee5b692a5a5ac1e7b1594067b9049 converted to 2 fields - let expected_sha_root = [ - 0x000000000000000000000000000000008e7d8bf0ef7ebd1607cc7ff9f2fbacf4, - 0x00000000000000000000000000000000574ee5b692a5a5ac1e7b1594067b9049 - ]; + // 31 byte truncated root hash + let expected_sha_root = 0xa0c56543aa73140e5ca27231eee3107bd4e11d62164feb411d77c9d9b2da47; assert(public_inputs.sha_root == expected_sha_root, "sha root does not match"); } 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 12f5e85e448..14a60b60dbb 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 @@ -1,18 +1,19 @@ use dep::types::{ - constants::NUM_FIELDS_PER_SHA256, hash::accumulate_sha256, }; // Note: Once we'll truncate sha256 to 1 Field we can nuke this and generalize the standard MerkleTree over different // hash functions. +// TODO(Miranda): This is an interim version with 1 field sha256 - ideally we remove this and use accumulate_sha256 inside +// the general MT struct Sha256MerkleTree { - leaves: [[Field; NUM_FIELDS_PER_SHA256]; N], - nodes: [[Field; NUM_FIELDS_PER_SHA256]; N], + leaves: [Field; N], + nodes: [Field; N], } impl Sha256MerkleTree { - pub fn new(leaves: [[Field; NUM_FIELDS_PER_SHA256]; N]) -> Self { - let mut nodes = [[0; NUM_FIELDS_PER_SHA256]; N]; + pub fn new(leaves: [Field; N]) -> Self { + let mut nodes = [0; N]; // We need one less node than leaves, but we cannot have computed array lengths let total_nodes = N - 1; @@ -22,30 +23,26 @@ impl Sha256MerkleTree { for i in 0..half_size { nodes[i] = accumulate_sha256( [ - U128::from_integer(leaves[2*i][0]), - U128::from_integer(leaves[2*i][1]), - U128::from_integer(leaves[2*i+1][0]), - U128::from_integer(leaves[2*i+1][1]) + leaves[2*i], + leaves[2*i+1] ] - ); + )[0]; } // hash the other layers for i in 0..(total_nodes - half_size) { nodes[half_size+i] = accumulate_sha256( [ - U128::from_integer(nodes[2*i][0]), - U128::from_integer(nodes[2*i][1]), - U128::from_integer(nodes[2*i+1][0]), - U128::from_integer(nodes[2*i+1][1]) + nodes[2*i], + nodes[2*i+1] ] - ); + )[0]; } Sha256MerkleTree { leaves, nodes } } - fn get_root(self) -> [Field; NUM_FIELDS_PER_SHA256] { + fn get_root(self) -> Field { self.nodes[N - 2] } } \ No newline at end of file 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 cf35cb187b3..bfc96d831ad 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, 69]; + let encrypted_logs_hash = [16]; let encrypted_log_preimages_length = 100; - let unencrypted_logs_hash = [26, 47]; + 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, 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, 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 558937cbf22..db5a167a1a3 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, 69]; + let encrypted_logs_hash = [16]; let encrypted_log_preimages_length = 100; - let unencrypted_logs_hash = [26, 47]; + 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, 429]; + let prev_encrypted_logs_hash = [80]; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956, 112]; + 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 cd8d2774dc5..abcb33195e3 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 @@ -437,10 +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([ - U128::from_integer(previous_unencrypted_logs_hash[0]), - U128::from_integer(previous_unencrypted_logs_hash[1]), - U128::from_integer(current_unencrypted_logs_hash[0]), - U128::from_integer(current_unencrypted_logs_hash[1]) + previous_unencrypted_logs_hash[0], + current_unencrypted_logs_hash[0], ]); // 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 0a59c0196cf..e783994c9a8 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, 47]; + 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, 429]; + let prev_encrypted_logs_hash = [80]; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956, 112]; + 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 3d5bf5df11e..cff94ecab8e 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, 47]; + 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, 429]; + let prev_encrypted_logs_hash = [80]; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956, 112]; + 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 0e544be77c4..3f301d0da55 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, 47]; + 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, 429]; + let prev_encrypted_logs_hash = [80]; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956, 112]; + 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/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index b06afdce361..6ca8dbd1eac 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 @@ -7,6 +7,7 @@ use crate::{ components::{compute_tx_effects_hash, compute_kernel_out_hash} }; use dep::types::{ + hash::sha256_to_field, abis::{ append_only_tree_snapshot::AppendOnlyTreeSnapshot, membership_witness::{ArchiveRootMembershipWitness, NullifierMembershipWitness, PublicDataMembershipWitness}, @@ -378,7 +379,7 @@ mod tests { base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs }, base::{state_diff_hints::StateDiffHints, base_rollup_inputs::BaseRollupInputs}, - components::{TX_EFFECTS_HASH_FULL_FIELDS, TX_EFFECTS_HASH_LOG_FIELDS, compute_kernel_out_hash} + components::{TX_EFFECTS_HASH_INPUT_FIELDS, compute_kernel_out_hash} }; use dep::types::{ abis::{ @@ -405,7 +406,7 @@ mod tests { kernel_data_builder::PreviousKernelDataBuilder, merkle_tree_utils::{NonEmptyMerkleTree, compute_zero_hashes}, sort::sort_high_to_low }, - utils::{field::full_field_less_than, uint256::U256} + utils::{field::{full_field_less_than, field_from_bytes_32_trunc, field_from_bytes}, uint256::U256} }; struct NullifierInsertion { @@ -938,9 +939,9 @@ mod tests { unconstrained fn empty_tx_effects_hash() { let outputs = BaseRollupInputsBuilder::new().execute(); - let hash_input_flattened = [0; TX_EFFECTS_HASH_FULL_FIELDS * 32 + TX_EFFECTS_HASH_LOG_FIELDS * 16]; + 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 = U256::from_bytes32(sha_digest).to_u128_limbs(); + 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]); } @@ -952,7 +953,7 @@ 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 = U256::from_bytes32(sha_digest).to_u128_limbs(); + 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]); } @@ -968,7 +969,7 @@ 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 = U256::from_bytes32(sha_digest).to_u128_limbs(); + 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]); 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 686ee06734e..72e2c47b46c 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 @@ -79,6 +79,8 @@ 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 * @@ -88,11 +90,9 @@ pub fn assert_prev_rollups_follow_on_from_each_other( pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { accumulate_sha256( [ - U128::from_integer(previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash[0]), - U128::from_integer(previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash[1]), - U128::from_integer(previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash[0]), - U128::from_integer(previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash[1]) - ] + 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], + ] ) } @@ -107,8 +107,8 @@ pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM } } - let sha_digest = dep::std::hash::sha256(hash_input_flattened); - U256::from_bytes32(sha_digest).to_u128_limbs() + let sha_digest = dep::types::hash::sha256_to_field(hash_input_flattened); + [sha_digest] } /** @@ -120,17 +120,13 @@ pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM pub fn compute_txs_effects_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { accumulate_sha256( [ - U128::from_integer(previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash[0]), - U128::from_integer(previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash[1]), - U128::from_integer(previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash[0]), - U128::from_integer(previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash[1]) + 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], ] ) } -global TX_EFFECTS_HASH_FULL_FIELDS = 195; -global TX_EFFECTS_HASH_LOG_FIELDS = 4; -global TX_EFFECTS_HASH_INPUT_FIELDS = 199; // TX_EFFECTS_HASH_FULL_FIELDS + TX_EFFECTS_HASH_LOG_FIELDS +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 @@ -142,8 +138,8 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM // 2 l2 -> l1 messages -> 2 fields // 32 public data update requests -> 64 fields // 1 contract deployments -> 3 fields - // 1 encrypted logs hash --> 1 sha256 hash -> 32 bytes -> 2 fields | Beware when populating bytes that it is only 32! - // 1 unencrypted logs hash --> 1 sha256 hash -> 32 bytes -> 2 fields | Beware when populating bytes that it is only 32! + // 1 encrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! + // 1 unencrypted logs hash --> 1 sha256 hash -> 31 bytes -> 1 fields | Beware when populating bytes that we fill (prepend) to 32! let mut txs_effects_hash_input = [0; TX_EFFECTS_HASH_INPUT_FIELDS]; let revert_code = combined.revert_code; @@ -196,23 +192,16 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM 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]; - for offset in 0..TX_EFFECTS_HASH_FULL_FIELDS { + let mut hash_input_flattened = [0; TX_EFFECTS_HASH_INPUT_FIELDS * 32]; + for offset in 0..TX_EFFECTS_HASH_INPUT_FIELDS { let input_as_bytes = txs_effects_hash_input[offset].to_be_bytes(32); for byte_index in 0..32 { hash_input_flattened[offset * 32 + byte_index] = input_as_bytes[byte_index]; } } - for log_field_index in 0..TX_EFFECTS_HASH_LOG_FIELDS { - let input_as_bytes = txs_effects_hash_input[TX_EFFECTS_HASH_FULL_FIELDS + log_field_index].to_be_bytes(16); - for byte_index in 0..16 { - hash_input_flattened[TX_EFFECTS_HASH_FULL_FIELDS * 32 + log_field_index * 16 + byte_index] = input_as_bytes[byte_index]; - } - } - - let sha_digest = dep::std::hash::sha256(hash_input_flattened); - U256::from_bytes32(sha_digest).to_u128_limbs() + let sha_digest = dep::types::hash::sha256_to_field(hash_input_flattened); + [sha_digest] } #[test] @@ -227,19 +216,3 @@ fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { + 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"); } - -#[test] -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" - ); -} - -#[test] -fn consistent_tx_effects_input_size() { - assert_eq( - TX_EFFECTS_HASH_INPUT_FIELDS, TX_EFFECTS_HASH_FULL_FIELDS + TX_EFFECTS_HASH_LOG_FIELDS, "tx effects hash input field size is incorrect" - ); -} - diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr index f2b9e6557c2..c42f8530432 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr @@ -132,12 +132,7 @@ mod tests { fn txs_effects_hash() { let mut inputs = default_merge_rollup_inputs(); let expected_hash = accumulate_sha256( - [ - U128::from_integer(0), - U128::from_integer(1), - U128::from_integer(2), - U128::from_integer(3) - ] + [1, 2] ); let outputs = inputs.merge_rollup_circuit(); 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 5494edf34d7..2a7dbfa4c9b 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}; +use dep::types::{constants::{NUM_FIELDS_PER_SHA256, 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. @@ -14,7 +14,8 @@ global NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES: u64 = 512; // Computes the messages hash from the leaves array // -// Returns the hash split into two field elements +// 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] { // Slice variation // let mut hash_input_flattened = []; @@ -35,12 +36,7 @@ fn compute_messages_hash(leaves: [Field; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP]) - } } - // Hash bytes and convert to 2 128 bit limbs - let sha_digest = dep::std::hash::sha256(hash_input_flattened); - // TODO(Kev): The CPP implementation is returning [high, low] - // and so is `to_u128_limbs`, so this matches. - // We should say why we are doing this vs [low, high] - U256::from_bytes32(sha_digest).to_u128_limbs() + [sha256_to_field(hash_input_flattened)] } #[test] @@ -59,18 +55,13 @@ mod tests { root::{root_rollup_inputs::RootRollupInputs, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES}, tests::root_rollup_inputs::default_root_rollup_inputs }; - use dep::types::utils::uint256::U256; + use dep::types::utils::{uint256::U256, field::field_from_bytes_32_trunc}; use dep::types::hash::accumulate_sha256; #[test] fn check_block_hashes_empty_blocks() { let expected_txs_effects_hash = accumulate_sha256( - [ - U128::from_integer(0), - U128::from_integer(1), - U128::from_integer(2), - U128::from_integer(3) - ] + [1, 2] ); let inputs = default_root_rollup_inputs(); 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 17a655ed282..f14909664eb 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 @@ -1,6 +1,6 @@ use crate::{ abis::{previous_rollup_data::PreviousRollupData, constant_rollup_data::ConstantRollupData}, - components, root::{compute_messages_hash, root_rollup_public_inputs::RootRollupPublicInputs} + components, root::{root_rollup_public_inputs::RootRollupPublicInputs} }; use dep::{ parity_lib::RootParityInput, @@ -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 a66ed609eef..9ef6c6920ee 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 = [0, 1]; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash = [2, 3]; + 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 = [0, 1]; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash = [2, 3]; + 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 f63103b1c14..738b2b7706d 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 @@ -21,7 +21,7 @@ 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], 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 7dcf72c2eae..8c8ac82db33 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 @@ -29,7 +29,7 @@ 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], 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 816e32c092d..53aad2456a3 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 @@ -33,7 +33,7 @@ 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], 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 be3c470d77e..8c6874e6749 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 @@ -12,7 +12,7 @@ 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], 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 09691ebef18..777457eb4dd 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 @@ -18,7 +18,7 @@ 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], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr index 58fd5f06ccc..55f60d7f130 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr @@ -75,6 +75,6 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x134b57e317f1554b9c4f547e617338fcc8ff04c6d96a278f1752b26a462c5d25; + let test_data_empty_hash = 0x135b1d61b12d391c14ff7aaae8bcff574a1e22afa20a5b59c67c1418d77fef72; assert_eq(hash, test_data_empty_hash); } 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 240726539ef..8bcaa685a50 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 @@ -35,7 +35,7 @@ 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], @@ -177,6 +177,6 @@ fn empty_hash() { let hash = inputs.hash(); // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x2b5ba01a6b73b68b4f44196e2dea49afd4076333e2dee8eddc9186e080f18201; + let test_data_empty_hash = 0x0f16478dc1731c940b04c312d322697f6a3bff523d2660d896426b2ab3af9598; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr index 0c6eea6e7c8..7ffb978ddf1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr @@ -69,7 +69,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item request hash" test - let test_data_call_stack_item_request_hash = 0x02e15f4157b5e2cb0a7ec3dfec18c6812ef16e1da319b364e5a11e337dfca414; + let test_data_call_stack_item_request_hash = 0x141bbf6bc30f0a19640983354528288239b68edd5c1edd9955a007801230d7b6; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } @@ -87,7 +87,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item hash" test - let test_data_call_stack_item_hash = 0x0f22ddeca80a2c6f455165f1d2d1950c5e1b772bdc312742d1de089b424f0f5f; + let test_data_call_stack_item_hash = 0x05e9e448563aa811c209cc557136ac56b55f9f2f31ee54d41b697389fd45dc1c; assert_eq(call_stack_item.hash(), test_data_call_stack_item_hash); } } 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 71fb097f4b7..a243b7a3dfb 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 @@ -35,7 +35,7 @@ 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], // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the @@ -149,6 +149,6 @@ fn empty_hash() { let hash = inputs.hash(); // Value from public_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x083ac560a513d670a7f50f0a3052d42cb9816b7b643e62025b8278652ad637ab; + let test_data_empty_hash = 0x0f1eb4e352e8dab6cbab3c63b6d8f3cd2cd90cc7ae5ff142e4dfa2b3e28e01c1; assert_eq(hash, test_data_empty_hash); } 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 1209bd5d764..0e830324671 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,8 @@ global L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH: u64 = 12; // MISC CONSTANTS global FUNCTION_SELECTOR_NUM_BYTES: Field = 4; -// sha256 hash is stored in two fields to accommodate all 256-bits of the hash -global NUM_FIELDS_PER_SHA256: u64 = 2; +// 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 @@ -147,7 +147,7 @@ global VIEW_NOTE_ORACLE_RETURN_LENGTH: u64 = 212; // LENGTH OF STRUCTS SERIALIZED TO FIELDS global AZTEC_ADDRESS_LENGTH = 1; global CALL_CONTEXT_LENGTH: u64 = 7; -global CONTENT_COMMITMENT_LENGTH: u64 = 7; +global CONTENT_COMMITMENT_LENGTH: u64 = 4; global CONTRACT_INSTANCE_LENGTH: u64 = 6; global CONTRACT_STORAGE_READ_LENGTH: u64 = 2; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: u64 = 2; @@ -155,19 +155,19 @@ global ETH_ADDRESS_LENGTH = 1; global FUNCTION_DATA_LENGTH: u64 = 2; global FUNCTION_LEAF_PREIMAGE_LENGTH: u64 = 5; global GLOBAL_VARIABLES_LENGTH: u64 = 6; -global HEADER_LENGTH: u64 = 23; // 2 for last_archive, 7 for content commitment, 8 for state reference, 6 for global vars +global HEADER_LENGTH: u64 = 20; // 2 for last_archive, 4 for content commitment, 8 for state reference, 6 for global vars global L1_TO_L2_MESSAGE_LENGTH: u64 = 6; global L2_TO_L1_MESSAGE_LENGTH: u64 = 2; global NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; global NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; global PARTIAL_STATE_REFERENCE_LENGTH: u64 = 6; -global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = 213; +global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = 208; // Change this ONLY if you have changed the PrivateCircuitPublicInputs structure. // In other words, if the structure/size of the public inputs of a function call changes then we should change this // constant as well PRIVATE_CALL_STACK_ITEM_LENGTH -global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 210; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 205; // Change this ONLY if you have changed the PublicCircuitPublicInputs structure. -global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 202; +global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 198; global STATE_REFERENCE_LENGTH: u64 = 8; // 2 for snap + 8 for partial global TX_CONTEXT_DATA_LENGTH: u64 = 4; global TX_REQUEST_LENGTH: u64 = 8; // 2 + TX_CONTEXT_DATA_LENGTH + FUNCTION_DATA_LENGTH 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 298da60b543..5c0061d4e01 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 @@ -2,7 +2,7 @@ use crate::{ constants::{NUM_FIELDS_PER_SHA256, 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], 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 c02e7e6b729..fbb6996c78d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -4,7 +4,7 @@ use crate::abis::function_selector::FunctionSelector; use crate::abis::contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage; use crate::contract_class_id::ContractClassId; use crate::abis::side_effect::{SideEffect}; -use crate::utils::uint256::U256; +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, GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__VK, @@ -18,20 +18,7 @@ use dep::std::hash::{pedersen_hash_with_separator, sha256}; pub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field { let sha256_hashed = sha256(bytes_to_hash); - - // Convert it to a field element - let mut v = 1; - let mut high = 0 as Field; - let mut low = 0 as Field; - - for i in 0..16 { - high = high + (sha256_hashed[15 - i] as Field) * v; - low = low + (sha256_hashed[16 + 15 - i] as Field) * v; - v = v * 256; - } - - // Abuse that a % p + b % p = (a + b) % p and that low < p - let hash_in_a_field = low + high * v; + let hash_in_a_field = field_from_bytes_32_trunc(sha256_hashed); hash_in_a_field } @@ -125,18 +112,16 @@ pub fn compute_l2_to_l1_hash( sha256_to_field(bytes.storage) } -// Computes sha256 hash of 2 input hashes stored in 4 fields. -// -// This method is bn254 specific. Two fields is needed in order to -// encode the sha256 output. It can be abstracted away with any 4-2 hash function. +// Computes sha256 hash of 2 input hashes. +// +// NB: This method now takes in two 31 byte fields - it assumes that any input +// is the result of a sha_to_field hash and => is truncated // // 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 // -// Returning a Field would be desirable because then this can be replaced with -// poseidon without changing the rest of the code -// -pub fn accumulate_sha256(input: [U128; 4]) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn accumulate_sha256(input: [Field; NUM_FIELDS_PER_SHA256 * 2]) -> [Field; NUM_FIELDS_PER_SHA256] { // 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 @@ -145,32 +130,29 @@ pub fn accumulate_sha256(input: [U128; 4]) -> [Field; NUM_FIELDS_PER_SHA256] { // only occupies 128 bits. // // TODO(David): This does not seem to be getting guaranteed anywhere in the code? - // - // Concatenate 4 u128 bit integers into a byte array. + + // Concatentate two fields into 32x2 = 64 bytes + // accumulate_sha256 assumes that the inputs are pre-truncated 31 byte numbers let mut hash_input_flattened = [0; 64]; - for offset in 0..4 { - let input_as_bytes = input[offset].to_be_bytes(); - for byte_index in 0..16 { - hash_input_flattened[offset * 16 + byte_index] = input_as_bytes[byte_index]; + for offset in 0..input.len() { + let input_as_bytes = input[offset].to_be_bytes(32); + for byte_index in 0..32 { + hash_input_flattened[offset * 32 + byte_index] = input_as_bytes[byte_index]; } } - let sha_digest = dep::std::hash::sha256(hash_input_flattened); - - U256::from_bytes32(sha_digest).to_u128_limbs() + [sha256_to_field(hash_input_flattened)] } pub fn compute_logs_hash( - previous_log_hash: [Field; 2], - current_log_hash: [Field; 2] + previous_log_hash: [Field; NUM_FIELDS_PER_SHA256], + current_log_hash: [Field; NUM_FIELDS_PER_SHA256] ) -> [Field; NUM_FIELDS_PER_SHA256] { accumulate_sha256( [ - U128::from_integer(previous_log_hash[0]), - U128::from_integer(previous_log_hash[1]), - U128::from_integer(current_log_hash[0]), - U128::from_integer(current_log_hash[1]) - ] + previous_log_hash[0], + current_log_hash[0] + ] ) } @@ -229,7 +211,15 @@ fn smoke_sha256_to_field() { 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159 ]; let result = sha256_to_field(full_buffer); - assert(result == 0x142a6d57007171f6eaa33d55976d9dbe739c889c8e920f115f7808dea184c718); + + assert(result == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184c7); + + // to show correctness of the current ver (truncate one byte) vs old ver (mod full bytes): + let result_bytes = sha256(full_buffer); + let truncated_field = crate::utils::field::field_from_bytes_32_trunc(result_bytes); + assert(truncated_field == result); + let mod_res = result + (result_bytes[31] as Field); + assert(mod_res == 0x448ebbc9e1a31220a2f3830c18eef61b9bd070e5084b7fa2a359fe729184e0); } #[test] @@ -246,10 +236,11 @@ fn compute_var_args_hash() { fn compute_l2_l1_hash() { // All zeroes let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(0), 0, 0, L2ToL1Message::empty()); - assert(hash_result == 0x2266ac2f9f0c19c015239ef5ea85862fc6fac00db73779b220a4d49c4856c2e1); + assert(hash_result == 0xb393978842a0fa3d3e1470196f098f473f9678e72463cb65ec4ab5581856c2); + // Non-zero case let message = L2ToL1Message { recipient: EthAddress::from_field(3), content: 5 }; let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(1), 2, 4, message); - assert(hash_result == 0x0f24729168d4450a5681beafa5e3a899ac28bd17bf5a4877dab37bcd834e1634); + assert(hash_result == 0x3f88c1044a05e5340ed20466276500f6d45ca5603913b9091e957161734e16); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/header.nr b/noir-projects/noir-protocol-circuits/crates/types/src/header.nr index 57ec93f228d..7b388e65532 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/header.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/header.nr @@ -4,7 +4,7 @@ use crate::{ global_variables::{GlobalVariables, GLOBAL_VARIABLES_LENGTH} }, constants::{ - GENERATOR_INDEX__BLOCK_HASH, HEADER_LENGTH, NUM_FIELDS_PER_SHA256, STATE_REFERENCE_LENGTH, + GENERATOR_INDEX__BLOCK_HASH, HEADER_LENGTH, STATE_REFERENCE_LENGTH, CONTENT_COMMITMENT_LENGTH }, hash::pedersen_hash, state_reference::StateReference, traits::{Deserialize, Empty, Hash, Serialize}, @@ -103,6 +103,6 @@ fn empty_hash_is_zero() { let hash = header.hash(); // Value from new_contract_data.test.ts "computes empty hash" test - let test_data_empty_hash = 0x124e8c40a6eca2e3ad10c04050b01a3fad00df3cea47b13592c7571b6914c7a7; + let test_data_empty_hash = 0x2a45c01b78a6b9a2392b7490966b41f47e5d9ac95610fa3eabe99d9aec7f6ad0; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr index 37f30d7216c..e7d7c0271bc 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr @@ -5,7 +5,7 @@ mod note_hash_read_requests; use crate::{ abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables}, - address::{AztecAddress, EthAddress}, constants::NUM_FIELDS_PER_SHA256, + address::{AztecAddress, EthAddress}, grumpkin_point::GrumpkinPoint, content_commitment::ContentCommitment, header::Header, partial_state_reference::PartialStateReference, state_reference::StateReference, tests::fixtures }; 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 b73d01c659d..1c3f4c344f8 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 @@ -33,7 +33,7 @@ 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], 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 2e36a6396f9..169cfb4bcd4 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 @@ -28,6 +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_log_preimages_length: Field, historical_header: Header, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr index 68dbc41e81a..abbbc0a5a05 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr @@ -14,6 +14,26 @@ pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field { as_field } +// Convert a 32 byte array to a field element by truncating the final byte +pub fn field_from_bytes_32_trunc(bytes32: [u8; 32]) -> Field { + // Convert it to a field element + let mut v = 1; + let mut high = 0 as Field; + let mut low = 0 as Field; + + for i in 0..15 { + // covers bytes 16..30 (31 is truncated and ignored) + low = low + (bytes32[15 + 15 - i] as Field) * v; + v = v * 256; + // covers bytes 0..14 + high = high + (bytes32[14 - i] as Field) * v; + } + // covers byte 15 + low = low + (bytes32[15] as Field) * v; + + low + high * v +} + // TODO to radix returns u8, so we cannot use bigger radixes. It'd be ideal to use a radix of the maximum range-constrained integer noir supports pub fn full_field_less_than(lhs: Field, rhs: Field) -> bool { lhs.lt(rhs) @@ -22,3 +42,24 @@ pub fn full_field_less_than(lhs: Field, rhs: Field) -> bool { pub fn full_field_greater_than(lhs: Field, rhs: Field) -> bool { rhs.lt(lhs) } + +#[test] +unconstrained fn bytes_field_test() { + // Tests correctness of field_from_bytes_32_trunc against existing methods + // Bytes representing 0x543e0a6642ffeb8039296861765a53407bba62bd1c97ca43374de950bbe0a7 + let inputs = [84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28, 151, 202, 67, 55, 77, 233, 80, 187, 224, 167]; + let field = field_from_bytes(inputs, true); + let return_bytes = field.to_be_bytes(31); + for i in 0..31 { + assert_eq(inputs[i], return_bytes[i]); + } + // 32 bytes - we remove the final byte, and check it matches the field + let inputs2 = [84, 62, 10, 102, 66, 255, 235, 128, 57, 41, 104, 97, 118, 90, 83, 64, 123, 186, 98, 189, 28, 151, 202, 67, 55, 77, 233, 80, 187, 224, 167, 158]; + let field2 = field_from_bytes_32_trunc(inputs2); + let return_bytes2 = field.to_be_bytes(31); + + for i in 0..31 { + assert_eq(return_bytes2[i], return_bytes[i]); + } + assert_eq(field2, field); +} \ No newline at end of file diff --git a/noir/noir-repo/noir_stdlib/src/field.nr b/noir/noir-repo/noir_stdlib/src/field.nr index 0f4c2caffdf..b876bcc967b 100644 --- a/noir/noir-repo/noir_stdlib/src/field.nr +++ b/noir/noir-repo/noir_stdlib/src/field.nr @@ -97,7 +97,7 @@ pub fn modulus_be_bytes() -> [u8] {} #[builtin(modulus_le_bytes)] pub fn modulus_le_bytes() -> [u8] {} -// Convert a 32 byte array to a field element +// Convert a 32 byte array to a field element by modding pub fn bytes32_to_field(bytes32: [u8; 32]) -> Field { // Convert it to a field element let mut v = 1; diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index e2a666d6f54..46f9aef2146 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -42,7 +42,7 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore } from '@aztec/kv-store'; import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; import { initStoreForRollup, openTmpStore } from '@aztec/kv-store/utils'; -import { SHA256, StandardTree } from '@aztec/merkle-tree'; +import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { AztecKVTxPool, P2P, createP2PClient } from '@aztec/p2p'; import { GlobalVariableBuilder, @@ -428,8 +428,8 @@ export class AztecNodeService implements AztecNode { } const treeHeight = Math.ceil(Math.log2(l2ToL1Messages.length)); - - const tree = new StandardTree(openTmpStore(true), new SHA256(), 'temp_outhash_sibling_path', treeHeight); + // The root of this tree is the out_hash calculated in Noir => we truncate to match Noir's SHA + const tree = new StandardTree(openTmpStore(true), new SHA256Trunc(), 'temp_outhash_sibling_path', treeHeight); await tree.appendLeaves(l2ToL1Messages.map(l2ToL1Msg => l2ToL1Msg.toBuffer())); return [indexOfL2ToL1Message, await tree.getSiblingPath(BigInt(indexOfL2ToL1Message), true)]; diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index d4823630c0c..fcabae1c013 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -1,7 +1,7 @@ import { L2BlockL2Logs, TxEffect } from '@aztec/circuit-types'; import { sha256 } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer, truncateAndPad } from '@aztec/foundation/serialize'; import { inspect } from 'util'; @@ -50,7 +50,7 @@ export class Body { const left = layers[activeLayer][i]; const right = layers[activeLayer][i + 1]; - layer.push(sha256(Buffer.concat([left, right]))); + layer.push(truncateAndPad(sha256(Buffer.concat([left, right])))); } layers.push(layer); diff --git a/yarn-project/circuit-types/src/l2_block.test.ts b/yarn-project/circuit-types/src/l2_block.test.ts index fc923ce5fb3..1642e644c77 100644 --- a/yarn-project/circuit-types/src/l2_block.test.ts +++ b/yarn-project/circuit-types/src/l2_block.test.ts @@ -16,7 +16,7 @@ describe('L2Block', () => { // The following 2 values are copied from `testComputeKernelLogsIterationWithoutLogs` in `Decoder.t.sol` const encodedLogs = Buffer.from('0000000400000000', 'hex'); const logs = TxL2Logs.fromBuffer(encodedLogs, true); - const referenceLogsHash = Buffer.from('1c9ecec90e28d2461650418635878a5c91e49f47586ecf75f2b0cbb94e897112', 'hex'); + const referenceLogsHash = Buffer.from('006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b39', 'hex'); const logsHash = logs.hash(); expect(logsHash).toEqual(referenceLogsHash); @@ -27,7 +27,7 @@ describe('L2Block', () => { // The following 2 values are copied from `testComputeKernelLogs1Iteration` in `Decoder.t.sol` const encodedLogs = Buffer.from('0000000c000000080000000493e78a70', 'hex'); const logs = TxL2Logs.fromBuffer(encodedLogs, true); - const referenceLogsHash = Buffer.from('1aa06a32df232f0d94b4735cffd46671c29dd1d4aec7cd562f856e643b4df833', 'hex'); + const referenceLogsHash = Buffer.from('00f458589e520e9e9bdaf746a7d226c39124e4a438f21fd41e6117a90f25f9a6', 'hex'); const logsHash = logs.hash(); expect(logsHash).toEqual(referenceLogsHash); @@ -41,7 +41,7 @@ describe('L2Block', () => { 'hex', ); const logs = TxL2Logs.fromBuffer(encodedLogs, true); - const referenceLogsHash = Buffer.from('6030bd40b448d1075bfaaebf0a0c70407598df13d04c44e95454aab642fadcb2', 'hex'); + const referenceLogsHash = Buffer.from('0084c3495a8cc56372f8f1d1efc0512920dae0f134d679cf26a12aff1509de14', 'hex'); const logsHash = logs.hash(); expect(logsHash).toEqual(referenceLogsHash); @@ -55,7 +55,7 @@ describe('L2Block', () => { 'hex', ); const logs = TxL2Logs.fromBuffer(encodedLogs, true); - const referenceLogsHash = Buffer.from('5e7f868e0f851f68a2c6f0b091512f99424fcedaabe02d4b087c0066112d72e8', 'hex'); + const referenceLogsHash = Buffer.from('00fb7a99b84aad205b5a8368c12a5a6b2dc19e5d623a601717b337cdadb56aa4', 'hex'); const logsHash = logs.hash(); expect(logsHash).toEqual(referenceLogsHash); diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 66809f662c9..b8535432dfd 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -2,7 +2,7 @@ import { Body, TxEffect, TxHash } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, Header, STRING_ENCODING } from '@aztec/circuits.js'; import { sha256 } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; import { makeAppendOnlyTreeSnapshot, makeHeader } from './l2_block_code_to_purge.js'; @@ -148,7 +148,7 @@ export class L2Block { this.body.getTxsEffectsHash(), ); - return Fr.fromBufferReduce(sha256(buf)); + return toTruncField(sha256(buf))[0]; } /** diff --git a/yarn-project/circuit-types/src/logs/function_l2_logs.ts b/yarn-project/circuit-types/src/logs/function_l2_logs.ts index bb03a91d2dd..5d544d299f0 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.ts @@ -1,6 +1,6 @@ import { randomBytes, sha256 } from '@aztec/foundation/crypto'; import { Fr, Point } from '@aztec/foundation/fields'; -import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; +import { BufferReader, prefixBufferWithLength, truncateAndPad } from '@aztec/foundation/serialize'; import { LogType } from './log_type.js'; import { UnencryptedL2Log } from './unencrypted_l2_log.js'; @@ -44,7 +44,7 @@ export class FunctionL2Logs { public hash(): Buffer { // Remove first 4 bytes that are occupied by length which is not part of the preimage in contracts and L2Blocks const preimage = this.toBuffer().subarray(4); - return sha256(preimage); + return truncateAndPad(sha256(preimage)); } /** diff --git a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts index e6257ed02f0..09fa81dc2af 100644 --- a/yarn-project/circuit-types/src/logs/tx_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/tx_l2_logs.ts @@ -1,5 +1,5 @@ import { sha256 } from '@aztec/foundation/crypto'; -import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; +import { BufferReader, prefixBufferWithLength, truncateAndPad } from '@aztec/foundation/serialize'; import isEqual from 'lodash.isequal'; @@ -134,7 +134,7 @@ export class TxL2Logs { logsHashes[1] = logsFromSingleFunctionCall.hash(); // privateCircuitPublicInputsLogsHash // Hash logs hash from the public inputs of previous kernel iteration and logs hash from private circuit public inputs - kernelPublicInputsLogsHash = sha256(Buffer.concat(logsHashes)); + kernelPublicInputsLogsHash = truncateAndPad(sha256(Buffer.concat(logsHashes))); } return kernelPublicInputsLogsHash; 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 551753c8061..248162c52ce 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 { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer, toTruncField } 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 Fr.fromBufferReduce(sha256(serializeToBuffer(...this.toFields()))); + return toTruncField(sha256(serializeToBuffer(...this.toFields())))[0]; } static fromBuffer(buffer: Buffer | BufferReader): L1ToL2Message { diff --git a/yarn-project/circuit-types/src/mocks_to_purge.ts b/yarn-project/circuit-types/src/mocks_to_purge.ts index 7b28f2366df..28cb2a2c292 100644 --- a/yarn-project/circuit-types/src/mocks_to_purge.ts +++ b/yarn-project/circuit-types/src/mocks_to_purge.ts @@ -20,6 +20,7 @@ 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, @@ -144,8 +145,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(2, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(2, fr, seed + 0x800), // unencrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, 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_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index cb55e688b8e..cf51aca0ed1 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -10,7 +10,13 @@ import { import { assertRightPadded, makeTuple } from '@aztec/foundation/array'; import { padArrayEnd } from '@aztec/foundation/collection'; import { sha256 } from '@aztec/foundation/crypto'; -import { BufferReader, Tuple, assertLength, serializeArrayOfBufferableToVector } from '@aztec/foundation/serialize'; +import { + BufferReader, + Tuple, + assertLength, + serializeArrayOfBufferableToVector, + truncateAndPad, +} from '@aztec/foundation/serialize'; import { inspect } from 'util'; @@ -86,6 +92,8 @@ export class TxEffect { } hash() { + // must correspond with compute_tx_effects_hash() in nr + // and TxsDecoder.sol decode() assertLength(this.noteHashes, MAX_NEW_NOTE_HASHES_PER_TX); assertRightPadded(this.noteHashes, Fr.isZero); const noteHashesBuffer = Buffer.concat(this.noteHashes.map(x => x.toBuffer())); @@ -101,7 +109,6 @@ export class TxEffect { assertLength(this.publicDataWrites, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX); assertRightPadded(this.publicDataWrites, PublicDataWrite.isEmpty); const publicDataUpdateRequestsBuffer = Buffer.concat(this.publicDataWrites.map(x => x.toBuffer())); - const encryptedLogsHashKernel0 = this.encryptedLogs.hash(); const unencryptedLogsHashKernel0 = this.unencryptedLogs.hash(); @@ -115,7 +122,7 @@ export class TxEffect { unencryptedLogsHashKernel0, ]); - return sha256(inputValue); + return truncateAndPad(sha256(inputValue)); } static random( diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 7a355ba42fc..f9e907a3dbb 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -58,7 +58,7 @@ 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 = 2; +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; @@ -83,7 +83,7 @@ export const MAX_NOTES_PER_PAGE = 10; export const VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; export const AZTEC_ADDRESS_LENGTH = 1; export const CALL_CONTEXT_LENGTH = 7; -export const CONTENT_COMMITMENT_LENGTH = 7; +export const CONTENT_COMMITMENT_LENGTH = 4; export const CONTRACT_INSTANCE_LENGTH = 6; export const CONTRACT_STORAGE_READ_LENGTH = 2; export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; @@ -91,15 +91,15 @@ export const ETH_ADDRESS_LENGTH = 1; export const FUNCTION_DATA_LENGTH = 2; export const FUNCTION_LEAF_PREIMAGE_LENGTH = 5; export const GLOBAL_VARIABLES_LENGTH = 6; -export const HEADER_LENGTH = 23; +export const HEADER_LENGTH = 20; export const L1_TO_L2_MESSAGE_LENGTH = 6; export const L2_TO_L1_MESSAGE_LENGTH = 2; export const NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; export const NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; export const PARTIAL_STATE_REFERENCE_LENGTH = 6; -export const PRIVATE_CALL_STACK_ITEM_LENGTH = 213; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 210; -export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 202; +export const PRIVATE_CALL_STACK_ITEM_LENGTH = 208; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 205; +export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 198; export const STATE_REFERENCE_LENGTH = 8; export const TX_CONTEXT_DATA_LENGTH = 4; export const TX_REQUEST_LENGTH = 8; 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 37bb4cec567..d0b5e308a32 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": "0x1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c6459bf87c9726c0877c974cd9e4f9f1eb609376ff35b049bf8057c126c7a657c026cfa45e069b3cb37a096ca375fe63b0c9b363ecb32fcfffb781ad4ae7b1aff8709ddf0236e94b857d94a53fdc66b0499f46ec1b2bfd5237824dfa16639f4ce91fbe1e6cd2c71ffb02ca7b1a6bc126efda601f34795f6a35d8f6ea3cf67d92efd0ac04db749d5f01b63fe8fc72b03da4f3b782edf73aff15d87ea7f38bc0f6a0cebf05b6dfeafc12b03da0f32f82ed373aff02d8eed7f9e7c1769fcee3bb6cbfd6f95d60fb4ce7f11daa693abf136cbfd2797c77e75e9ddf0eb65feafc73609baaf3cf826d8ace2f04db2f747e01d87eaef3f3c13659e7e781ed673a3f176c93747e0ed87eaaf3b3c1365ee76781ed273a3f136ce3747e06d8c6eafc3360fbb1ce3f0db61fe9fc9760bb5be71783ad85ce2f059b8c1989fd540a75fe6db0b5d279ec7f24dff79f08b6c3747e02d8dae87c2dd8e4db70a3c126e341d7802da1f3d5603b42e7abc026e767c3c126e39f0c039b9c4b0d055b7b9d1f023639ef190c3619cf7210d8e41ba47dc176b4ce57824dbead5f01b663757e3fd864ccb137c126dfaddb0b36198bf911b0c9f7aaa783ed249dff03d8641c9687c0768aceff1e6ca7eafcefc026dff07c106c253aff5bb075d4f907c076baceff066c3246d6fd603b53e7ef039b8c1dfc6bb0c9f79e3f035b279d9f06b67374fe576093b144ee059b8c0ffa4bb075d6f9a96093ef704f01db053aff0bb0c9787f3f079b7c637832d8645cb79f81adabce4f025b99ceff146cdd747e3cd8ca75fe2760ebaef3e3c0d643e7c782ada7ceff186cbd74fe4760ebadf3d2cea8fd59ede7fbf47c3288efbc4cf9fb30a83f35746d200cc813e7b97631f0a0af3db1d7bd2c755e2ffb7d0bbd5e89a13de07b77ecbed3d7141fe87515eaf5ee367c1742997374e3a09693637e4bbddc5e6339bc8f25eb96652e04fb2e63dded757d3f7054dfdd069370a30e52e67ccda48e8d3fd0f936b04c8c6ca9eb6389b50034c42909796170a35559299ef73686e703e0d9133b4ffa7add454ce0be15f7f5ba791fd78cb56228b31bf4dbe5403fdcd765dd322ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f3332b9e7d3a8fcf95a5dc3e1246b1ed011e17f7f9f139acac5f3dd7d9755a9ddf3db1fbadff7caf955e6fa951e74228f3353c73daabf345f07fd96e51dbd2c173c206b7a5f82b82fae0b3a07d8e78f6183c7b2c5a48be2436df6523dd685c56aafaada867ec7b0d5df7593475b5bfeed1eb2a3034c5fdf54383079f8d1601ef47fa3701ebf908eae0601f6f302ec41fee4b7bc026f90f81d1c576c66389b407f23c1c9f4d4b995f19cfc5e3dff665a52edb8df7a14ec9e0c0f82e8432bf83b6ef739dc7be21fb40b77f58fe2f5343cfa9453f55e71df1d739b57db7036712fca0eff7803526dff5dea129d049fc88bd10f27f87fe1c524ef410ad851dc72b477673b90f8de58aa1cc4e4bfd9341bcf5df61f0ec3098d536f912e2ec1f70fc77d526ed8cd0e842d048caec018df63ae2d963f00887f8536564fbb736cac8b28550e67f411ba5ea22edbcd413fbb6e031c0d5714c7cc9ba65de766efc01309a7554f131f0d83ade3db1f3e656ffafc34ad2bfd8aec7d5ff4bd6dd5e2f2b1c81b1fe5258bf70b50ea28f2dffb37d4bead6efb27fd95ea3cec2823a4b997625e95f156797e97c26e7fa87eaba2dea5c7fa7039e4450ffda5b4d0d1ddff118f3be031e47f52cb51dbb7619752a86329da09e0ece631a7c177807f876b1cd510b3987da6d685108653a96a47fa5ed88d211af553fc84a5dcaace783a596ba48994e2575756903f638995c6eb7f7a04e6abd7b2c759532e797d4e9d245e713b09df0be495fcbff656aa83dc0b178b6c65fe7d4f6dd029c49f083bedf05d6987cd7fb16889cef8b1fb11742beb2a4aeac94133d446b6157fb88bcf387ece672bb8de58aa1cc364bfd9341bcf5df6af06c3598d536e95a5297973872d96e6e8bd0a81434923278ff588eedf8de9dedb8bfc71177d4717f0f309aed269ebbb864db6bb099f7506de7835206cfc9a4ccd525e95fd5ce262c65cd7bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7401fb1e9d179dbb18da1542994125e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1f434aeab871ecc43dfab7086c9fe85f47d769e5b67b86c261bb6738bca48e1d9715ae8f2d7531af915b0407de53ffda288bf7dd1a5acecc9be3502a7d3f31cad9fce0354f6cef6a742d2d45a61681fd7ec187067b4170e0989bb21f60cc99f751ba18ebc1fb28b525e95f6993ccb26adbfffbd175fac87614edb03dc198fc1018933a5ffacda6aeb6facbbcf8538c1f197570d376a5df57cae43ef05ee071d1b63b6aa34bf1181bdff7297a57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0dcac800708c550600", + "bytecode": "0x1f8b08000000000000ffed9d77781447baee5b20e22001ced9c2f6ae033616424409189c73c6c618631002830d88689c713639384772cec1648c0163eccdd9bbeb0db677d71bce7dee73ef9fe79c7b8fefed9aa9efe8a5a81e3472d7f04a53fd3ca5a9fe54dddfafdefeba3a55771504e9e95f612ad0f9a661ba20387a92ff27f56fe9779b3ac7b8ae52979c050d84b34903e16cda40380b1b0867b306c2d9bc8170b668209c2d1b0867ab18390b80cf156feb06c69b6860bc6d828611b7450d84b3b88170b66d209ced1a0867fb06c2794203e13cb181709ed440384f6e209ca73410ce531b08e7690d84f3f406c2794603e13cb381709ed54038cf6e209ce73410ce731b08674903e1ecd04038cf6b209ce7c7c8d91138e55efef7f4eff7f5ef85faf722fd7bb1febd44ff76d4752cd4f39786e9b230750ad3e5c6ff9430ea867e5998ba18ff2b0f53d730750b5377fdbf12fdbf1e61ea19a65e61aa085365987a87a94f98fa6a3dfa85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bbc2d43f4c7787e91e83654098ee0dd3c030dd17a64161ba3f4c83c3f440988684696898aac2342c4cd5611a1ea611617a304c23c3342a4c0f85e9e1308d0ed398308d0d534d98c685697c98268469629826856972981e09d31443b347c3f458981e0fd31306e793617a2a4c4f87696a989e09d3b3617a2e4ccf87e98530bd18a697c2f47298a685697a9866846966986685697698e684696e98e685697e985e09d3ab617a2d4caf87e98d30bd19a6b7c2f47698de09d3bb9a457684f7c2f47e98168469619816856971989684696998968569799856846965985685697598d684696d98d685697d9836846963983685697398b684696b983e08d3b6306d0fd38e30ed0cd3ae30ed0ed39e30ed0dd38761da17a68fc2b43f4c07c274304c1f87e950983e09d3e1307d1aa6cfc2f48330fd304c3f3234ff71987e12a69f86e967daf673fdfb0b5d56f6f95feadf5fe9df5febdfdfe8dfcf8df2bf35e67f67ccff5eff7ea17fffa07fffa87fffa47fffac7fbfd4bf5fe9dfaff5ef5ff4ef5ff5efdff4ef37faf7effaf71ffaf79ffa573dff7bb5433adf32a89d92414c6d52f9f0a1eafebf886d3e5f54cfae9aeaffc96f89b617ea79f92dd0f6667abe99616faee79b1beb69a9e75b1af6623d5f6cd8dbe9f97686fd043d7f82613f49cf9f64d83be8f90e604fe8ffa52b96fe51b6a6da54003689cf26606ba66d4dc1d65c5607b616dad60c6cb27d9b83ad95b6b5005b6b6d6b09b684b6b5122dc3d446db92415cb1523a54adb728eef5ea6726c5f1f356a9f5b675c4db2e7ede616abded1df0aaf83841afab08e2e6446d2b06db49dad6166c276b5b3bb09da26dedc176aab69d00b6d3b4ed44b09dae6d2781ed0c6d3b196c676adb29603b4bdb4e05dbd9da761ad8ced1b6d3c176aeb69d01b6126d3b136cbac90dce02db79da7636d8ced7b673c07681b69d0b3639c72b019b9cef75009b9cfb9d0736390f3c5fdb54dbd1aa00fc69bbb45b297fd26683edfbd25e83ed4269abc17691b4d360bb187c8bed12686bc4d651dba4dd52ffeba5f3c920aefda42cb59f54c4bdde70cd6abdbde35f6feaf95d9fa056eb24f8a900adfaea7c8c7d5b3aa36f39b7113f622f84fc0d5056ca891e72ec1176752ca8d4f9be1996eb652c570c652a2df54f06f1d6bfb7c1d3db606e06793731dba5d4c76c9da7ac6376009435634fce831a63ccde0c1c0e62b6dcc76c9da7ac6376049435634fce851b63ccde071c0e62b6879b982d2bf5319bbe371604f6d893eba1c618b3a38023fe98edea63b6ee53d631fb1c9435634fae891b63cc4e018ef863b67b0f7f6e50e729eb989d0765cdd893fb338d31665f040e07313bccb7b3759eb28ed90550d68c3db957d81863f655e0883f667b3a8ad92e3e6683f473ce20b0c79edcb76e8c31bb1838e28fd961fefe6cdda7ac6376379435634f9ea134c698dda8f3ea39c3cff57386b3c0f60b6d3b1b78e38fedea3247b1ddd9c776baff4710d863549ee735c6d8fe48e7551cff0afa2388edd7d257016cbfd1b6f3c0f6b9b69d0ff572b00f74f7fb40ddeb94ed3ef047286bc6b23c5b6e8cfbc02f80c341ccf6f0315bf73a651bb3ff0665cdd8937e0e8d3166bf040e0731dbd3c76cddeb946dccfe3b943563ef229d6f8c31fb3f755e9d2f7ca1cf172e01db1fb4ad23d8fea86d9782ed4fda7619d8feac6d9dc0f6a5b65d0eb6afb4ad146c5f6b5b67b0fd45dbcac0f6576deb02b6bf695b39d8bed1b6ae60fbbbb67503db3fb4ad3bd8fea96d3dc0f62f6deba96daa9f9ef4bd3aac6d2d813f19c4bb6da5dfa5ac5be63be7c0775bc377db1cfa6e6ff86e6ff15de6c077027cc85460cc27215fe696a7b41878d05779fcbebaa8ba7709ea5ef772e0e9eaa0ee09f051179eaec0d32d7e9ed4f1b37bfceb4d6de32e86a609f0d505ead5c341bd0ac097ac5be6c55f31d8b06ded6161ec193f635901f89275cb7c4f60141bb6f5f22e95ec3fea787861412daf837d29754e24fee4db55c2510e76297371875ab68e9aad08fe8fc7bd6e86cd515ca6e2427cc9ba655efc15417dbae59eb1acae8c5d0d46576d4401f892757bdfb5db41f2781c7771ad636bd3c477450e7cf7347c971bbeb1ed9429d3b1ad2730c77ecda98f6d95f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfa5a0b6ac94133da41d167615cbb22d91dd5cae87b15c3194a9b0d43f19c45bff4a83a7d26056dbe44a38163ad81f5231506170c87c39685719a15d056827652e02ed5cb567bd0c1e99ef063cd28e75071e57d744513cb9b81e3b966f3c87c5eb67f93f9e07b8da5e9d0d4699b76daf9ec0683b5771703d93f15ca52b308aad17f07471a459d476ed42e2db41aca4da23f121e7e6b2ff7603bb94e9a95fa8536de543d056ba88118c4799ea7acd1bff762a4b5d8377cd8207b79d83ebaace8ee2b114efdf7c1bc41b6b66bbd4d5d02aea1e8fabb6bc8bc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae1b09a3d9ffcdd57dfed4370cf5ba64fdeab9ceff71da1facac14fbc7483f884b8c3a174299a226b565ff1ff407339f53611fc96e6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77fa5b942e9eb7a93ed6ea3b9a66dfcf6e164d5df47f464d0b0c4db13ffea5068f8ad3caa6b56c2e9efd65fb2c12b5927c9ccff68a037bacc7bf5dca8e7866dd2438b2fdc0e38cabfe3bd256cbf3f20ac377219439b349edb691be5532ce6c176339ecf723eb96652e017ba5b1ee767a59e16866acbf3b2c2b65ce8136f540935acd1cb49565d9f65dc7e7e6f11f87d3cff1bb64c1d319785cb4338ece378ef8de6adccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c8431477d1f52cf33e45b65b2fed4f7829bd4fa75fd1c4e9e397534ea8cef8efeef26b565b7ea7c5170747f87a86de9eafb1451db52fce1b767f059908be7ba05e04bd65d66d142f225b1f92e733636843cc7ef62e85a6ed1d4d5fe8acf585153dc5fbb1a3cf86c34eadb3e6586cd65dfa1a8b8107fb82f95814df2f87eb48bed8cc712b35f8ff8c3e7d73fd2dab60b5c6dfbb25297ed067e3725191c1ddff83d959f43dbf74b9dc73e1cd877e46bcbff65caf49c5af4537576f07dcdd20258976c5fdbb73dfb016b4cbe3be3ba0a74ea67685008f9af9ad49695725256b41676b58fc8376090dd5caeabb15c3194e963a97f3288b7fee6b756fb1acc6a9bfc06e2ec6b38febb6a93fa446874096824651c7fb3d1dabfd2ec5788ed6873a38c2c8bdfa2fb17b45151fd476dc700d7c73159b7ed38661e17ead2cf33dffb69fd07b41771f7d3fa0f8821eca71518ebef08eb17aee641f4b145cafc97b17ef39c5c96c17e60ffbd9fc0f75cca743e9b73f2e3757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c6badb56cb3ca08ee9e96658b229615adcc6f85150547ebe7e63b6be97dbeaf5117896bfc06b9943911eae2e6bc257d0ee8ea9b7249a893ca9759ea2a654e837ded0c9d4fc076c2fdf662cbff65ca740e8863b85f117f9d53dbf74ae04c821ff47d15b0c6e4bb33fa967340f123f642c85fd4b4b6ac94133d446b6157fb889c4721bbb95c85b15c3194e967a97f3288b7fe57183c5718cc6a9b9c0d717631f44377d556f78bd0a823682465f09ea2ed3ba0b67b1daededf883a97c2f797ccf32b3c4eba396fb29fc79af7d56ce7081d0d7e3c47e80eed6cc252d6bc5f28c7cb38fb0de3bb12ddc12fbe2be1eadbcdbd40b724cce379c1f1f4ede23bb6ca5fd49809bd72e03b6acc845cf86e6ff86e9f43df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b028c2ec6724804477e7bfc588c38be832cd714185d1c1fb2fdf679776094e50a81d1c5bba538fe465d18f11bc3789c174607df8aed5cdf6fc5e23dbde6c0c8f4ce263e9b6a018c2ece8bebfbae1e9ecfb7845f57e31275c982b10c1865b956c0e8e2de385ecbd48511af8b64b9d6c0e8e21956b6e33be1b7e7f1deb24bc64cc776c77d51cab2bdf752e99627e3b906fa7630ae614a0bbccf782c2d7abbe5c978ee83be1ddcf74b6981e30c1e4b0b7c36e862dcc34470e473b863f1e0f34b59ee04604c3a62ec9b05631218fffb5e3130f673c498cc82b11f308afd24607470ff35c5d82f0b46bc4f29cb9d0c8c573a62bc220bc62b8151963b05185ddc4b4d80dfba305e058cb2dca9c078b523c6abb260bc1a1865b9d380f11a478c5767c1780d30ca72a703e3b58e18afc982f15a6094e5ce00c6eb1c315e9b05e375c028cb9d098cd73b62bc2e0bc6eb8151963b0b186f70c4787d168c3700a32c773630dee888f1862c186f044659ee1c60bcc911e38d5930de048cb2dcb9c078b323c69bb260bc191865b91260bcc511e3cd5930de028cb25c0760bcd511e32d5930de0a8cb2dc79c0789b23c65bb360bc0d1865b9f381f176478cb765c1783b30ca721700e31d8e186fcf82f10e6094e5be078c773a62bc230bc63b815196fb3e30dee588f1ce2c18ef02c63b2d8cfd1d31de9505637f6094e52e05c6bbe3674c5d4bf7cf82f16ee0b9277e9e94667767c1738f5b9ed477f5eeb6f8ba377e5fa96d3120a87bddef059e81f1f3a4b6c5bd59f00843312c879add173f634ab3815930de073c83e2e74969765f163c8340b3fb2c9add1f3f634ab3415930de0f3c83e3e74969767f163c8341b3fb2d9a3d103f634ab3c159303e003c43e2e74969f640163c43825acd1eb06836347ec6946643b2601c0a3c55f1f3a4341b9a054f156836d4a2d9b0f819539a5565c1380c78aae3e74969362c0b9e6ad06c9845b3e1f133a634abce827138f08c889f27a5d9f02c78468066c32d9a3d183f634ab31159303e083c23e3e74969f660163c2341b3072d9a8d8a9f31a5d9c82c184701cf43f1f3a4341b9505cf43a0d9288b660f3b627c280bc6872d3c717f27fb218baf318eea3e3aa87bdd85a11896c37e12631d318ec982712c30ca72d84fa2c611e3d82c186b8051964b3866ccd44fa2067c8f8bdf77aa5daa09eaaecf38b73c19fb49a0eff18eb41817d45d8bf16e7932f69340df131c69313ea8bb16138067a2032d12e0a32e3cc2500ccb613f89498e182766c13809186539ec2731d911e3a42c182703a32c87fd241e71c438390bc647805196c37e12531c313e9205e3146094e5b09fc4a38e18a764c1f82830ca72d84fe231478c8f66c1f81830ca72d84fe271478c8f65c1f83830ca72d84fe209478c8f67c1f80430ca72d84fe249478c4f64c1f82430ca72d84fe229478c4f66c1f81430ca72d84fe269478c4f65c1f83430ca72d84f62aa23c6a7b3609c0a8cb21cf69378c611e3d42c189f0146590efb493ceb88f1992c189f054659ee61c78c99ae5f9e6de4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3fe7c077027cc85460cc27212f0cc5b0dcc39eb15133224f497c3ca55877f4f53c41dd9fb7f01438aa3bfa7a81a0eec2d0d0189f6b008c0f370046af63ba0f627d1815cf8bf0ff648c3c2f64c1f322f0bce488e7c52c785e029e97e3e749c5d44b59f00843312cf77003607cae01307a1dbd8e4c8c5ec7fcd1d1337a46cfe8198f07634368c33d638388c7b2fa322a9e69f1f3a4347b390b9e69a0992c778f5bc6b2fa322a9ee9f1f3a4349b9605cf74d06c9a4533078c65f565543c33e2e74969363d0b9e19a0d9748b660e18cbeacba87866c6cf93d26c46163c3341b31916cd1c3096d59751f1cc8a9f27a5d9cc2c78668166332d9a39602cab2fa3e2991d3f4f4ab35959f0cc06cd66593473c058565f46c533277e9e9466b3b3e099039acdb668e680b1acbe8c8a676efc3c29cde664c13317349b63d1cc0163597d1915cfbcf879529acdcd82671e6836d7a2192be3c30d80f1b906c0e858c7b2fa322a9ef98e78e665c1331f785e71c4333f0b9e5780e7d5f8795231f54a163cc2500ccb3ddc00189f6b008c5e47af2313a3d7317f74f48c9ed13366c7f87c0360f4dbda33b2323ab8becaf80ecd2b8ddc77d43b348ddd77d43b348dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97e2d7edf65d97e63e635e071f1cd1b47f52c55eb7d5dafebdb18f5535abd6168f58aa1553194791df47bc3817e05e057d62df3e22f5be60b09981df92e53ed4b2ba8bff878ced043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7316df986f16d49eb7cbf74fd53aded2f9423d2fe59f07bb9499d822fddb2ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff57e680273078820c3cf3c8782693f1cc24e31949c633888ce756329e2bc9789e24e32927e31947c6338c8ce76e329e1bc8782e27e3e943c633858ca72719cf2c329e87c8785e22e3194cc6733b19cfd5643c4f93f19491f14c20e3194ec6732f19cf4d643c49329ec7c878ba93f15c4cc633868c673619cf45643c43c8785e26e3b9938ca7988ca72d19cfb5643c2f90f15c46c65341c6f30c19cf5c329e49643c0f92f1dc47c6534ac6730b194f27329e2bc8789e20e3e94ac633878ca7868c671a194f15194f7f329e4bc878ae27e3694ac6d39b8c673e19cf23643cbdc8784691f17424e3b99f8ce736329eabc8789e22e3e942c6339e8c673a194f3519cf00329e1bc978fa92f13c4ac6d3838c673419cf85643c0f90f1dc41c6938bef9966c3d3868ca7888ce71a329e67c978a692f17426e39948c633838c670419cf40329e9bc978fa91f13c4ec6d38d8c672c19cf50329ebbc8785e24e36947c6d39e8ce73a329e02029e4470f4182609f8ff6b606b622cab3efb3aba43edffdfd6f626b0cc3b3adfd4b2eeb7c126df927dc7b22ceaf436d425a9f3a5df6d4ae984be92302ffe8a80e31d129eebc878da93f1b423e379918ce72e329ea1643c63c978ba91f13c4ec6d38f8ce766329e81643c23c8786690f14c24e3e94cc633958ce759329e6bc8788ac878da90f1bc46c6730719cf03643c1792f18c26e3e941c6f328194f5f329e1bc9780690f15493f14c27e3194fc6d3858ce729329eabc8786e23e3b99f8ca72319cf28329e5e643c8f90f1cc27e3e94dc6d3948ce77a329e4bc878fa93f15491f14c23e3a921e39943c6d3958ce709329e2bc8783a91f1dc42c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643c1791f1cc26e31943c67331194f77329ec7c87892643c3791f1dc4bc6339c8c6702194f1919cfd3643c5793f1dc4ec633988ce725329e87c8786691f1f424e39942c6d3878ce772329e1bc878ee26e31946c6338e8ca79c8ce749329e2bc9786e25e31944c633928c672619cf64329e79643c95169ed71cf1c8fbeeb26e997f8dc4b783ed50aad6fbaea33abda7d7d54caf57f8c55f219499da3afdabde0fc76585cbfc3e01be9bf31e68f49ea3bac8f62830b60ffa7ecb916f79474bd62df36f3572df6d0ddf6df3c4777bc377fb3cf1ede3dcc7793ef8f671eee33c1f7cfb38f771cee4dbc1b541197e274da602633e0979bc5e70f17d3947f53ce23af1db18f5535abd6f68655e5b1543997741bff71de867bbf69479f1972df38504cc18172541bc71b120fe3a95a976ab15e8bac0d017ebb5d091a651c790858ddc77d431a4b1fb8e3a863476df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe17e97c8cd78da5e8433d5f94eb8145e07789ce17c4e857ad6bb15e57a15eb7702c01bb94f94f78aee9f779bfcfc7e5db1fdb7c9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8668e73332ffdc52f023657fdf9a3623117ef121c4fdf51b1d8d87d47c56263f7ede3dcc73993efa50e7c27c0874c99faf82d059ec50e781cd533f56c639951a7d78c3a1543193cc62f7350cf02f02beb96f965c0235325f0b88883ba6c73e49947c633998c672619cf48329e41643cb792f15c49c6f324194f3919cf38329e61643c7793f1dc40c67339194f1f329e29643c3dc9786691f13c44c6f31219cf60329edbc978ae26e3799a8ca78c8c670219cf70329e7bc9786e22e34992f13c46c6d39d8ce762329e31643cb3c9788690f1bc4cc67327194f31194f5b329e6bc9785e20e3b98c8ca7828ce719329eb9643c93c8781e24e3b98f8ca7948c672119cf2d643c9dc878ae20e379828ca72b19cf1c329e1a329e69643c55643cfdc9782e21e3b99e8ca729194f6f329ef9643c8f90f1f422e31945c6d3918ce77e329edbc878ae22e3798a8ca70b19cf78329ee9643cd5643c03c878de27e3b9918ca72f19cfa3643c3dc8784693f15c48c6f30019cf1d643c6dc8788ac878ae21e379968c672a194f67329e89643c33c8784690f10c24e3b9998ca71f19cfe3643cddc878c692f10c25e3b98b8ce745329e76643cedc978ae23e32920e0490447bffb9f80ffbf0f367947fd35b02dd7f9c5606b62f1d154e79781ad50e7651d2dc234a5c3d1eb469d5cbd978fbe92302ffe8a80633909cf75643cedc978da91f1bc48c6731719cf50329eb1643cddc8781e27e3e947c6733319cf40329e11643c33c8782692f17426e3994ac6f32c19cf35643c45643c6dc878ee20e379808ce742329ed1643c3dc8781e25e3e94bc6732319cffb643c03c878aac978a693f18c27e3e942c6f31419cf55643cb791f1dc4fc6d3918c6714194f2f329e47c878e693f1f426e3694ac6733d19cf25643cfdc978aac878a691f1d490f1cc21e3e94ac6f30419cf15643c9dc8786e21e35948c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643cb3c978c690f15c4cc6d39d8ce731329e2419cf4d643cf792f10c27e39940c65346c6f33419cfd5643cb793f10c26e379898ce721329e59643c3dc978a690f1f421e3b99c8ce706329ebbc9788691f18c23e32927e379928ce74a329e5bc9780691f18c24e39949c633998c671e194f658e78d4bbedd2d73a002e9c92905f063c0b1df038aa67297ed7e0db18d7abb45a6168f5bea1553194590afaad70a05f01f89575cbfc0ae07956e76ddf54789684516c0b1df324a0ce3265da0756008f8b7dd2513d53b1bad2a8d3b316dda50cc6ea4a07f5b4ed3b32bf12785ed079614d40b9174818c5b6cc314f02ea2c53a6585d093c2ef61d47f54cc5ea2aa34e2f5874973218abab1cd4d3b6efc8fc2ae07951e7853501e55e246114db0ab73ce509a8b34c99627515f0b8d8771cd53315abab8d3abd68d15dca60acae76504fdbbe23f3ab613b7866cf6c63563c72ff5e581350ee251246b1ad74ca535e9a803acb94a91d5b0d3c2eda7947baa7dab135469d5eb2e82e653056d738a8a76ddf91f93516df2541bc5aacad83166b2d3c6b73ac85f8cb9679690364f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e6266d059f1c8f709853501e55e266114db2ab73ca9f7825e0e8e9c0a8cf924e4d702cf6a07fa38aa67aa0ff93aa34e2f5b749732b87fad73504fdbbe23f3eb603b64c3bca601327b9debc7ac78a6e9bcb026a0dc341246b1ad76cb936ac7a605474e99dab175c0e3a29d7754cf543bb6dea8d3348bee5206f7aff50eea69db77647e3d6c07cfec996dcc8a67bace0b6b02ca4d276114db5aa73c65a9f71ba707474e99dab1f5c0e3a29d77a47baa1ddb60d469ba45772983b1bac1413d6dfb8ecc6f80ed900df39a06c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9df34767c53343e7853501e56690308a6d9d539e2ea9e70e338223a74ccf1d36008f8be7328e744f3d77d868d4698645772983fbd74607f5b4ed3b32bf11b64363675ed300997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd479614d40b999248c625bef9627f5dd8399c19153a67e3b1b816783037d1cd533d56f679351a79916dda50cee5f9b1cd4d3b6efc8fc26d80e9ed933db9815cf2c9d17d604949b45c228b60d6e7952edd8ace0c829533bb609785cb4f38eea996ac7361b759a65d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3755e5813506e3609a3d836bae549b563b38323a74cedd866e071d1ce3baa67aa1ddb62d469b645772983b1bac5413d6dfb8ecc6f81ede0993db38d59f1ccd179614d40b939248c62dbe4982701759629533bb605785cb4f38eea996ac7b61a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd256114db66c73c09a8b34c9962752bf0b8d8771cd53315ab1f18759a6bd15dca60ac7ee0a09eb67d47e63f009e793a2fac0928378f84516c5b1cf324a0ce32658ad50f80c7c5bee3a89ea958dd66d4699e45772983b1bacd413d6dfb8ecc6f039ef93a2fac0928379f84516cd88ecd77c45364f01459b4385ebe9516153adf46ff26e0ff15c0e8aa6d996f30ca3cc6b8d88a72a0595b83a7ada1d9f1f4adb4a884bc9a707b550223c3f66a9b03cdda1b3ced0dcd8ea76fa5456f9d6fa77f717bf5064686edd51e781cb4cfe50983474d998edddb1cebe3a89ea963f7f6c0ae3b1e87a40c1ebbb73ba8a7ed5c42e6b7c376f0cc9ed9c6ac78faebbcb026a05c7f1246b1e139ff8ef879ca13068f9a32b5633b1cebe3a89ea9766c6760d77d07e82e653056773aa86701f89575cbfc4ed80ed930af6980cc5ee7fa312b9e013a2fac0928378084516cdb816757fc3ce50983474d99dab15d8ef57154cf543bb63bb0ebbe0b749732b87fed7650cf02f02beb96f9ddb01db2615ed30099bdcef563563c03755e5813506e2009a3d87602cf9ed879d263be208f9a32b5637b1cebe3a69ee9766c6f60d77d0fe82e6570ffdaeba09e05e057d62df37b613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c83745e5813506e1009a3d87603cf87b1f3a49f3b208f9a323d77f8d0b13e6eea997eeeb02fb0ebfe21e82e653056f739a86701f89575cbfc3ed80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf609d17d604941b4cc228b6bdc0f351fc3ce50983474d999e3b7ce4581f47f54c3d77d81fd875ff0874973218abfb1dd4b300fccaba657e3f6c87fd9ed9335b9815cf109d17d604941b42c228b67dc07320769ef4f353e45153a676ec80637ddcd433dd8e1d0cecba1f00dda50cc6ea4107f52c00bfb26e993f08db211be6350d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63ae78fce8aa74ae7853501e5aa4818c5b61f783e8e9da74b69c2e0515381319f84fcc78ef57153cff4738743815df78f41772983fbd72107f52c00bfb26e993f04dba1b133af6980cc3e3672c3ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc0cb1a178aa755e581350ae9a84516c0781e793f879ca13068f9a0a8cf924e43f71ac8fa37aa6faed1c0eecba7f02ba4b19dcbf0e3ba86701f89575cbfc61d80e9ed933db9815cf089d17d604941b41c228b643c0f3a9039e84c1a3a64cedd8a78ef57154cf543bf65960d7fd53d05dca60ac7ee6a09e05e057d62df39f01cf489d17d604941b49c228b6c3c0e32256154f91c123f39f12f8565ad4e87c1bfd8bdbab061819b657510e346b6bf0b435343b9ebe9516e320af26dc5ee38091617bb5cd8166ed0d9ef68666c7d3b7d262bcceb7d3bfb8bdc60323c3f66a9f03cd8e677b783cf7ede319a75ef3e3a779c171d4bce0386a5ee035a7d2dcc1f1a50c8f650130e09484fc67c0f3c3f87952f7b83ecb82e787c0f383f8793a3baa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308aed07c0e3a2dd5075bf4caf4bd6df2c4cfb4eaaf5ebe2d903de776da6d72b1ce2af10cadc5e525bf6a0662b82ffcb7653f53964d81cbd0fdcd9f60c4ce6c55f5190bbfba099eecba2162e9edd647bdc3f64e1f9363e9e52dccfd1d7414775cfe639da410b4f8c75ef1cf50cf140fc754fb51f9df4ba64fd6a1ffdfc24a79a97e3be27ed4727a3ce8550e6b292dab25f40fb616b2b5cef9b724e6eee9b4d82daf64cb84ab4dd7cbef2adb64bb94fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3199fe9bb1874f9845433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb4f2c3af6b670f726e066dcaf7b1b3ab26976acfdbabf85bb3f0137e37edddfd0914db363edd7032cdc0308b819f7eb01868e6c9a1d6bbf1e68e11e48c0cdb85f0f347464d3ec58fbf5200bf720026ec6fd7a90a1239b66c7daaf075bb807137033eed7830d1dd9343bd67e3dc4c23d84809b71bf1e121ca9239b66c7daafab2cdc5504dc8cfb7595a1239b66c7daafab2ddcd504dc8cfb75b5a1239b66c7daaf4758b847107033eed7230c1dd9343bd67e3dd2c23d92809b71bfae6bbf7dd6fdbac6c25d43c0cdb85fd7183ab26976acfd7a9c857b1c0137e37e3dced0914db363edd7e32ddce309b819f7ebf1868e6c9ad9f66b47efe59565fb9ee061a7faa4c76b3e9c05cfc7c0e322a61cc541a9a37e2ea9bea9070cad0e1b5ae1381807413f077d6132bedf2ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e3370ef1f98a94fb8484516cf84ccac57d7e55f7cbf5ba64fdcdc2d4f9945abf0763f75b565a60f84b0287f82b8432ff794e6dd9ae9aad28387abbe1b8d6b82df7c75e87f4b634e35fe6c55f11d4e700f038783f3fc573d0e03968d102df3b8dc777d930371a9795aaefefb40a6ab7f37ea33ea8e947b1fb3f52d30243d38f1cfb4e04476e4f61c0290979e471f16cd8513d536dc13ea34ea6c6c550e642a8e73e07f52c00bfb26e99df073c3235011e573118183c81451f992ac9782693f18c24e3b9808c671019cf69643cb792f1b422e3b9928ce749329e72329e71643cc3c878ce25e3b99b8ce744329e1bc8782e27e32924e3e943c633858ca72719cf43643cdf27e3194cc6732919cf19643cb793f124c878ae26e3799a8ca78c8c670219cf70329e0e643cf792f19c4cc67313194f73329e2419cf63643cddc9782e26e31943c6731119cf10329eb3c878ee24e32926e3694bc6732d19cf33643c15643c9791f14c22e379908ce77c329efbc8784ac9784e25e3b9858ca71319cf15643c2dc9789e20e3e94ac65343c65345c6730e194f7f329e4bc8784e20e3b99e8ca729194f6f329e47c8787a91f18c22e3e948c6f33d329efbc9784e27e3b98d8ca73519cf55643c07c8789e22e3e942c6339e8ca79a8ce710194f0919cf00329e93c8786e24e36946c6d3978ce751329e1e643ca3c9782e24e379808ce74c329e3bc878da90f11491f15c43c633958ca73319cf44329e11643ce791f10c24e339858ce766329e16643cfdc8781e27e3e946c633968c672819cfd9643c7791f1b423e3694fc6731d194f01014f2238fa5b4c09f8ff41b0c937833e065b13cbfae439b59457c7c5673b1cbdee2696757f6461409d3e84ba2475bef4bb4d299dd05712e6c55f11707c44c2731d194f7b329e76643c7791f19c4dc633948c672c194f37329ec7c978fa91f1b420e3b9998ce714329e81643ce791f18c20e39948c6d3998c672a19cf35643c45643c6dc878ee20e339938ce701329e0bc9784693f1f420e379948ca72f194f33329e1bc9784e22e31940c65342c673888ca79a8c673c194f17329ea7c8780e90f15c45c6d39a8ce736329ed3c978ee27e3f91e194f47329e51643cbdc8781e21e3e94dc6d3948ce77a329e13c8782e21e3e94fc6730e194f15194f0d194f57329e27c8785a92f15c41c6d3898ce716329e53c9784ac978ee23e3399f8ce741329e49643c9791f15490f13c43c6732d194f5b329e62329e3bc978ce22e31942c6731119cf18329e8bc978ba93f13c46c69324e3694ec6731319cfc9643cf792f17420e3194ec633818ca78c8ce769329eabc97812643cb793f19c41c6732919cf60329eef93f13c44c6d3938c670a194f1f329e42329ecbc9786e20e339918ce76e329e73c9788691f18c23e32927e379928ce74a329e56643cb792f19c46c633888ce702329e91643c93c9782ac9789a183cf87ff56ed8019d976f0715c2ffefd69dcbdbe97549197946acee55ec356caabe7b1cd5776f503b25617e0fd457d8f702cf5e473c1f1a3ca6ef22c8578266bb0d9b62dce58871b7c128f3bb8051f4db0d3cbb1df1ec31784cdf4590ef0d9aed346c8a718723c69d06a3ccef0046d16f27f0ec74c4b3cbe0317d1741be3f68b6ddb029c66d8e18b71b8c32bf0d1845bfedc0b3dd11cf0e83c7f45d04f901a0d907864d316e75c4f881c128f35b8151f4fb00783e70c4b3cde0317d17417e2068b6c5b029c6cd8e18b7188c32bf191845bf2dc0b3c511cf5683c7f45d04f941a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37711e40783661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf45901f029aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d1741be0a345b63d814e36a478c6b0c46995f0d8ca2df1ae059e38867adc163fa2e827c3568b6cab029c6958e1857198c32bf121845bf55c0b3ca11cf6a83c7f45d04f911a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37711e4478266cb0c9b625cea887199c128f34b8151f45b063ccb1cf12c37784cdf4590af01cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be8b203f0e345b64d814e342478c8b0c46995f088ca2df22e059e48867b1c163fa2e82fc78d06c8161538cef3b625c6030cafcfbc028fa2d009e058e78161a3ca6ef22c8df0936e1ed05b6f774be27d8ded5f91e607b47e7bb83ed6d9def06b6b774be2bd8ded4f972b0bda1f35dc0f6bace9781ed359def0cb65775be0fd85ed1f9be609baff349b0cdd3f97e609babf357806d8ece5f09b6d93a7f15d866e9fcd5609ba9f3d7806d86ce5f0bb6e93a7f1dd8a6e9fcf5607b59e76f00db4b3a7f23d85ed4f99bc0f682cedf0cb6e775fe16b03da7f3b782ed599dbf0d6c0febfced60bb47e7ef00db619dbf0b6c9feafcdd60fb4ce7ef05db0f74fe3eb0fd50e7ef07db8f74fe01b0fd58e78782ed273a3f0c6c3fd5f9e160fb99ce3f08b69febfc28b0fd42e71f02db2f757e34d87ea5f363c0f66b9d1f0bb6dfe8fc04b07daef313c1f65b9d9f04b6dfe9fc64b0fd5ee71f01db173a3f056c7fd0f947c1f6479d7f0c6c7fd2f9c7c1f6679d7f026c5feafc9360fb4ae79f02dbd73aff34d8fea2f353c1f6579d7f066c7fd37969d7543bfb779d2f09e26d67bf096aa712f02dfe54997fe87c73a38c2c5b08655aeb0e85ea19877a7749da616997954ddae1f7c026edf0bb609376f81db0493bfc36d8a41d7e0b6cd20ebf09366987df009bb4c3af834ddae1d7c026edf0ab609376f815b025757e3ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae119609376783ad8a41d9e063669875f069bb4c32f814ddae117c126edf00b609376f879b0493bfc1cd8a41d7e166cd20e3f0c366987ef019bec2fdf804ddae6c36093b6f953b049dbfc19d8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe15d8c6eafcafc1266df36fc0266df3e76093b6f9b76093b6f9776093b6f9f76093b6f90bb049dbfc07b049dbfc47b049dbfc27b049dbfc67b049dbfc25d8a46dfe0a6cd2367f0d36699bff02b667745edaea96609367c56a2afd8e138ec3d3047c094b3288b7edc7290979acbb4c95643cb3c8784692f1bc45c6730119cf20329ed3c8785a91f12c20e31947c6339f8c671919cf52329ef7c978ce25e3d944c6b3918ce744329ebd643c7bc8782e27e32924e39941c6f306198fbcf7c9c233988ce752329e33c87812643c73c9789690f12c26e379978ca70319cf06329ef5643c2793f1ec26e3d945c6d39c8ce71b329e69643c1793f1bc46c6731119cf10329eb3c8788ac978da92f15490f15c46c6339b8c671119cf42329eb7c978ce27e35947c6b3968ca7948ce754329e9d643c3bc8783a91f1b424e379898ca7868ce715329e2a329e73c878fa93f15c42c67302194f53329ede643cf790f1cc24e379938ca72319cff7c878d690f1ac26e3f92b19cfe9643cdbc978b691f1b426e33940c6339e8c671e194f3519cf7b643c87c8784ac8780690f19c44c6d38c8ce73019cf74329ed7c9785691f1ac24e339938ce703329ead643c6dc8788ac878e690f18c20e379878ce73c329e81643ca790f1b420e379998ce755329e15643ccbc978ce26e3d942c6b3998ca71d194f7b329e7d643c1f92f11410f0248023009bfcbf29d8e43b3c87c0f6b5ce1f009b7cc36701d8bed2f967c0f694c5d6c4c2270c53c126efca7e0d36b93ff334d8e49d89afc026e70de25fcd4fef70347f135846fc34b5f0a3bfaf2c5c92c7ed2dcb248378b737fa4a06f66fde15188cc79be743329e7d643cedc978da91f16c26e3d942c6733619cf72329e15643caf92f1bc4cc6d3828ce714329e81643ce791f1bc43c633828c670e194f11194f1b329ead643c1f90f19c49c6b3928c671519cfeb643cd3c9780e93f13423e339898c6700194f0919cf21329ef7c878aac978e691f18c27e33940c6d39a8c671b19cf76329ed3c978fe4ac6b39a8c670d19cff7c8783a92f1bc49c633938ce71e329ede643c4dc9784e20e3b9848ca73f19cf39643c55643caf90f1d490f1bc44c6d3928ca71319cf0e329e9d643ca792f19492f1ac25e35947c6733e19cfdb643c0bc9781691f1cc26e3b98c8ca7828ca72d194f3119cf59643c43c8782e22e3798d8ce762329e69643cdf90f13427e3d945c6b39b8ce764329ef5643c1bc8783a90f1bc4bc6b3988c670919cf5c329e0419cf19643c9792f10c26e3f93e19cf1b643c33c8780ac9782e27e3d943c6b3978ce744329e8d643c9bc878ce25e3799f8c672919cf32329ef9643ce3c8781690f1b422e3398d8c671019cf05643c6f91f18c24e39945c65349c6d3c4c273c8118f7c2b46d62df3871ab9ef3d86ef3d79e27b97e17b579ef8de61f8de9127beb719beb7e589efad86efad79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efa586efa579e27bb1e17b719ef85e68f85e9827be99afbf553f5ce9abbc4fff26e0ff15c0b8c011e3218351e61700a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba93dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba95dc0d3db114fd4bd92de04be9516f2eeb3bcf39780ffe378ebae62aab7c128f3b698da013cfd1df144dde3e94fe05b6921df0a936fd224e0ff383ea3ab98ea6f30cabc2da670fcdc018e78a2ee4d0d20f0adb4906fedca372f13f07f1cbfc9554c0d301865de1653387edc40473c51f7d40612f8565ac8b360f9467b02fe3f08185dc5d4408351e66d3185e3dd0c72c413752f7010816fa5c5609d973e5609f8ff6060741553830c4699b7c5d446e019ec8827ea1ee66002df4a8b213a2fef7024e0ff4380d1554c0d361865de1653eb816788239ea87baf43087c2b2daa745edee94fc0ffab80d1554c0d311865de16536b81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb10478c5506a3cc0f0146b1ad069e6a473c51f7baab097c2b2de4dbfeabf46f02fe8fe3b1ba8aa96a8351e66d3185e3418f70c413758f7e04816fa5c5489d97316112f0ff91c0e82aa646188c326f8b291cbf72a4239ea8670b23097c2b2de4db5ccbf46f02fe5f038cae626aa4c128f3b6985a0a3c358e78161b3c8b2d5a1c2fdf4a0be9cbbd44ff26e0ffe380d1554cd5188c326f8ba9c5c033ce114fd4b39c7104be9516f26ded45fa3701ff1f0f8cae626a9cc128f3b6985a083ce31df1443d831a9f03df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe8fe7b943beb6e7c7f3187a3c8f25fedac05f1be4cab73f96f86b835cf9ced76b03df9ee7be3d97ebaf8220fa7a6cb923df4b0ddf328fcf59963af2bdd8f02df3f8cc60b123df0b0ddf328ff7bf173af25d64f896f98539f0ddd6f0dd3687bedb1bbedb5b7cbbd8de89e0c8eb6f61c02909798c81450e781cd5b354ad77895ed7b731aed776dfc6dc5f8aa1cc12d0cf75db21ebced476b48ccf7769027cc837be944d9ec5be07366943df059b3c637f076cd2cebf0d3679bef316d8e4f9cf9b601ba9f387c126cf61b1ffbb3c4bdf01b62a9dc77ed743747e1bd8a45f12f6f795be655bc126fd03b19fa9f4f1dc0c36e9a78bfd1ba5aff546b0497f79ec5727ef3cac079bbcb782fdb9e4dda3b5603ba0f3d88f48bee9b21a6c53757e15d8fea2f32bc1f6a4cedf03b62f75fe1bb0fd59e71782ed099d5f04b63fe9fc12b03daef36f80ed8f3aff3ad81ed3f9d7c0f6a8cee37b617fd0f90fc1f685cee3fb4853747e0fd87eaff3f81ecc233abf0b6cbfd3f957c13659e75f01db249d9f0fb6dfeafc3cb07daef373c13651e7e780ed373a3f1b6c13747e16d87eadf333c13656e76780ed573a3f1d6c63747e1ad846ebfccb60fba5cebf04b65fe8fc5fc1f690ce2f065b139d5f0a36197f11fb7c14eafc72b0c9b8f4d89747be953f1e6c2d747e1cd85aea7c0dd8e43b6b23c126632b8f005b42e7abc1d646e7abc026e73a43c02663890c069b9c970c025b3b9d1f08363987180036191bb23fd8e47b9ebdc17692ce57824dbe535f01b65374fe10d864fcae0560936fc01d009b8c6bfc34d8e4dbcf53c176a6ceff056c32a6c993603b5be7bf04db393aff67b0c9f7309f005b89ceff096c1d74fe71b09da7f37f049b8c37f518d82ed0f947c126e3f0fe016cf2ede42fc076a1ce4f01db453aff7bb0c9b81c8f804dc6dafc1dd83aeafc64b0c937ad2781ed329dff2dd864ecbccfc126dfeb9d08361923ed3760ebacf313c056a6f3bf065b179d1f0bb6729dff15d8baeafc18b075d3f9d160ebaef3bf045b0f9dff05d87aeabcb4336a7f56fbf9413d9f0ce23dcffe383872ca749e2d0cc813e7796b31f0a0affdb1d7bd2c758e2cfb7d13bd5e89a1fde07b5fecbed3e7e71fe97515eaf5ee337c17429996ba7150cbc931bfa95eee80b11cde139275cb329783fd4363dded747d3f7254df7d069370a30e52a68d6652c7c68d3adf12968991ad4ced03126b0168885312f2c2e046abb2523cefad0bcf47c0b33f769ef4b5af8b98c07d2bee6b5ff39ea8196bc550661fe8f7a103fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac780eea3c3e579672074918c5b61f785cdce7c7e7b0b27ef55ce7fd736bfdee8fddef91cff79ae9f5961a752e84327f86674e8b75be08fe2fdb2d6a5b3a784e98715b8abf22a80f3e0b3ae88867bfc1b3dfa285e44b62f35d36cc8dc665a5aadf8a7ac67ec0d0f5a0455357fbeb7ebdae024353dc5f3f3678f0d96811f07ea27f13b09e4fa00e0ef6f18c7121fe705fda0f36c97f0c8c2eb6331e4ba43d90e7e1f86c5acaec329e8bc7bfedcb4a5db61b7ba14ec9e0e8f82e8432fba0eddbaff3d837e420e8f633cbff65caf49c5af45375de1d7f9d53db77177026c10ffade09ac31f93ee27d94029dc48fd80b21ff53e8cf21e5440fd15ad871ec6f643797fbd858ae18caecb1d43f19c45bffdd06cf6e83596d938f21ce7e06c77f576dd29e088d2e078da4cc7ed0e880239efd068f70883f5546b67f73a38c2c5b08657e0b6d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f147c068d651c547e7536a79f7c7cedbb0fa7ffd03da8bb8fb7ffd0362a800380263fda5b07ee16a1e441f5ba4ccff308ea32eae31705b9a7aa2ce52e67f413bf4fd92743e9b73fde375dd1675aebfc7014f2238f2da5b4d998eef788cd9eb80c7513d4b6dc7ae0f8d3a1543990ba19e0ece6332be57bb1b7cbbd8e6a8859c43ed33b42884320525e95f693ba274c46bd58f72529732ebf960a9a52e52a645496d5d5a823d4e2697db6d27d449ad77bfa5ae52a64d49ad2ec53a9f80ed84f74dceb6fc5fa64ced018e6bb33dfe3aa7b6ef36e04c821ff4fd01b0c6e4fb88ef6ac8f9bef8117b21e4cf2aa92d2be5440fd15ad8d53e22effc21bbb9dc3e63b96228b3c352ff64106ffdb71b3cdb0d66b54dda97d4e6258e5cb69b3b22342a058da40cde3f96633bbe77673beeef77c41d75dcdf0f8c66bb89e72e2ed90e186ce63d54dbf9a094c1733229d3b124fdabdad984a56cb3e0c87bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7402fb7e9d179d3b19da154299ae25e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1fbd4a6ab9711cc2fdfab7086c9fea5f47d769e5b67b86c261bb67982ca965c76585ebb0a52ee6357293e0e87beadf1a65f1be5ba6e5ccbc39a6a3d2f753a39ccd0f5ef3c4f6ae46e7d252646a12d8ef177c6cb01704478f5f29fb01c69c791fa593b11ebc8f726b49fa57da24b3acdaf69f9f54ab8f6c47d10edb138cc98f8131a9f3a5df6dea6cabbfcc8b3fc5f8895107376d57fa7da56cee031f001e176dbba336ba148fb1f17d9fa26795edf8ffb1a1550e9fd75a8ff9e633f796463e1edf65d5b6fb4f362df659785c3d4789d2629fc5777c5a741b663b7ed8b4c865df87282d3eb4f88e518b1178df3393167b2d3c2eee4565d262afc5777c5a742fcdf45c03b5d863e17175ef214a0bf1972df38704cc2d8d7c3cbecbab6cf7c96c5aecb6f0b8ba6e8ed262b7c5777c5a74ee86f7e83269b1cbc213fffdb9cc5aecb2f88e4f8b1e3df11e5e262d765a785c3dd38dd262a7c5778c7131dc762fc7a6c50e0bcf8e1c6bb1c3e23bc6f3c36eb67b6d362db65b781cdc77cda8c5768bef18b5188af75d3369b1cdc2b32dc75a6cb3f88e4f8baaaeb67bc2362d3eb0f0b8ba271ca5c50716dff16931b487f2bdb50e5a6cb5f06ccdb1165b2dbe63bc864ac5c5963a68b1c5c2b325c75a6cb1f88e4f8bead4b9d6e63a68b1d9c2b339c75a6cb6f88e4f8bd2d43175531db4d864e1d994632d36597cc71817a9ebc98d75d062a38567638eb5d868f11de3712415171beaa0c5060bcf861c6bb1c1e23b3e2d46a4ee3fadaf8316eb2d3ceb73acc57a8bef18efb9a4e2625d1db45867e15997632dd6597cc7a74597d431756d1db4586be1599b632dd65a7cc7a7c5f0d433b13575d0628d85674d8eb55863f11de37967aabd585d072d565b7856e7588bd516df319e77a6ee5facaa8316ab2c3cab72acc52a8bef18dbced479e7ca3a68b1d2c2b332c75aacb4f88ef1bc33a5c58a3a68b1c2c2b322c75aacb0f88ef1bc33751c595e072d965b7896e7588be516df31c645aaed5c56072d96597896e5588b6516df31ded74ab59d4beba0c5520b8fabf11aa2b4586af11de3f548ea1edf923a68b1c4c2b324c75a2cb1f88ef15951ea1c7c711db4586ce1599c632d1683ef03b1fb4ef7e7161fd217eb32438b4228f36d49fa57fa6245e928ebc07e65589745b1d725ddaf6c61445d16415da44c6187dabab40c9c8cf753eea8aea99859007552ebfdc4525729d3aa43ad2e099d4fc036390cba9d61f9bf4c05c67c12f2a29faaf37bf1d73915abef026712fca0ef77803526df9dd177814ee247ec85903fbd436d5929277a88d6c2aef691f7751ed9cde5161bcb154399f72df54f06f1d6ff3d83e73d83596d936288338923376d579ae9fd088d2e038da40cf6d9fbc4118fd9875038c49f2a23dbbfb95106fb504a99f3a08dc27ea552cf447074bf49476d5967649775cbbcf82b06db016034eba8e2631ff4fd94b122641c0965937121bac07aba1b3655d71e8eea2abe64dd32df0318659c8aeeb9672cab2b63378351f1f472a0198ebd2153a6e3452fe0e9e980c7513d53c7a10aa34e3d8c3a1543197cb7b1c2413d0bc0afac5be62bc0b78b6d8e5ac831f962438b42ac37b46799749475a8f8ed6ea94b1fc77591754bbbd42707be2b0ddf5d0ddf89e0c8ed1c0499f7af4a60eeed8059adb76ffceb2dc5f3368929f1d315ead40f3488ab4eb82e39cfeb67685b08f9fe709e27e5a4ac1cbf845dc5b26c4b643797eb652c570c65fa58ea9f0ce2ad7f5f83a7afc1acb6c90d706ee7607f48c5401f8343e6bb82767d23b4eb03da49193cfe7573a45d6f8347e6bb018f9ce354804dce15843f01ffef92036eb3ddabb0708b0dc789eb6661ec1a3f63ea5ca79bc128f35d81516cbd81a7d29166e6b6bed8d0078fcbcd8d32b26c219479088e8d094b59b5df5d58505bafa6da1edbbb63ba4d6fee402f1ca731007d0243c300f4927a3673c0d33aa81dab71e2a49a09431f1c7ec7f0f4a347412b3430f1b7c0528d2660c37c538b2d088e1c92b2106c32246533b0353164c1a130a5bc0c69e7422ed443d65d6870b60496387de3709e32650a9d16c0e3229455e8c8909e3a74ee99306ad2708c8f6606677d6247fdaf69867251eb72b51dcc7d2209f3660c163af2df14ea9b8479f1a7b68d0cad3a6ee8b087fb4d7870f298e163274d44a1cc1d1bf305c1911bc0fc8d12dcd54e87018015c6c6a199512f6c30e47fb2615ac7cf598e63e69ada04e04fa6d6a05b2b07baa9f5cbd8b7c3868e1e7ddbe4aad1a3865d3379ecb049a36ac6e2d66c692817b5a5e5ffcdc1666be2b1ac9ab0d9c2655b586cb60947196e09363972b5029bf0b4065b53c84b7973cb3809d70b60fdb24ba9ff29719ae98ab7086a43400ec7aa5d55fbaf3a95539f9055a7426a6863b539d5d0c5ea8ea11a9a587dc54e0d3dac861a56430b9f11a4870e5643059f1da48702565fbb2809d243fb9e17d40eddaba6c3c0f9bd203d34afba4d7351903eed5243eb760cd243e7aa5b979d82f467ded4bbf5eaf45ddd1650a7bcea124f9d7eaad34e7579a16e5fa85b59ea944e9d2eab534175faa62e47fa6aadfb85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bb82f4f0ce7707e9e1d7d5f0cff706e9a1a1ef0bd2c346df1fa487947e20480f373d34480f453d2c480f533d3c480f61fd60901ede7a54901e26f7e1203dd4ae1a82776c901e0e5b0d93ad86cf56c3fcaa2181d590c26aa861352cb11ac2580d81ac86467e3c480fb9ac866c7e2a480ffb3c354ccf84e9d9303d17a6e7c3f442985e0cd2c383ab61c3a705e961c6d5f0e33383f470e5b383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f06f86e9ad30bd1da41f49a84731ea1185bafdaf1e83a95bd48b82f4adf32541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a7f90be2d7e30483f2a55b7c3d5a301158feaf6fd6761fa41987e18a61f85e9c761fa49987e1aa69f85e9e7417a586335dcb11a2e590dadac8661564336aba19cd550d06ad8e82f82f4d0d36ae8ea3f05e921b1bf0cd35761fa3a480faffdd730fd2d4cdf84e9ef61fa4798fe19a67f05b54369636371866e61f4554a3074d2a4e163c64d2a9954533266f2e849a3c68d7eac64caa849234b6a1e193e61c4e89a29b8f00ff5c2320e78bf0913863e56326a6cf5f0474b6a264f2aa91951525533796cf51107ea7fea85ce3adae3d0eaea6867fffe5d48ff6f3d9db6d26d9f8cb07e7de6bab5695a0f414ea8cf42dd9ad6af4213f4514a2e67ef4c9feb964c1c5d33a9a4b4646cf8373cb8d64c195edda904ff37311479e2a4928993864e9854326242cd9892ce9d70bd4fb7ae4725fea3b51b985667d44f9c16fa5b4af50ab19de7d64381cfcfad1fe9dfbf0be9bfd5d369eac09b6d0d9bd767a14b4aea47585e1229cbc4c95593260c1d36297ae19edf65e1bef5a9e62df5ace67fd5c759d30ef558a84387fa11f6ad8fb35159380bfe3f244cae11d44d0600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77741cc791c667911856000892600e50a219c1c5228309cc99122559391024419116495024942ccb922cc939e76c399de59cf35917edbbf3390739e72839dd3ff77cefee3dbfeb9eed323e3467d6d8d5145883ad79afb03db5bd53bffea6ba77b67b7691090adb9f8c655cb9dad885c1d91b3ddfef1e734f6e6b4bf058394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c9352c23939259c5312e4b46c55c1e82d69dea90cba26cd984d99a6e7a540d3fa9469da90024d1b83748c51d352c2d99412cee929e19c9112ce9929e16c4e09e7ac9470ce4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09674b4a38cf4f09e70529e1bc30259c17a584f3e204395700e712f7f814f7b8d43d2e738fcbdd23bd66a57b5ce5da58e3f65b8dadb66cc6dabce7f2c6da8d7518ebf49eeb32d66dacc758af7baec53dd7676c8db1b5c6d6195b6f6c83d361a3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e3176a9b1fdc62e3376b9b12b8c3dd5d895c6ae3276b5b16b3c966b8d5d67ec7a633718bbd1d84dc60e181b3076d0d82163878d0d1a3b62ec6663478d1d33f63463b7183b6eec84b193c6868c9d3276abb1d3c6ce181b36769bb1db8ddd61ec4e6377799a3dddd8ddc69e61ec1e8ff399c6ee35769fb1fb8d3dcbd803c61e34f690b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1571b7b8db1d71a7b9db1d71b7b83b1371a7b9363a18ef066636f31f6b0b1b71a7b9bb1b71b7b87b1771afb3b63ef32f688b1771b7b8fb1f71a7b9fb1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb7b639f33f6a8b17f30f68fc6fec9d83f1bfb1763ff6aecf3c6be60ecdf8cfdbbb1ff30f64563ff69ec4bc6beec69fe15635f35f635635f77be6fb8c76fbaba342ff62d63df76e5c7dce377dce377dde3f7bcd77cdfd80f3cdf0f8dfdc8f3fdd8d84f5cf9a7eef167eef1e7eef117eef197eef157eef1d7eef137eef1b7eef171f7f8847bfc9d7bfcbd7bfc837bfca37bb46baa973617ca938391ad3f48688cea3892b36b2a24fe9260f466b5a876cfd1638bf3d7b87d7a24ed6add7eade7af73fb75de7126bbfdc99ebfc9ed3779fe196e7f86e76f76fbcd9e7fb6db9fedf92f72fb17813f1bc09cabf35b5fb57365c047f95a05be5ae7ab065f1d1d0e7c939caf167c747eebc037c5f926816faaf34d065fd6f9a69096c6ce73befe20a95cc90dd8e3d6277d5cb70ed5903cef217bdc4626de69c9f30edae33631f0dafc98ee8e350df26686f335816fa6f34d079f1b82fedae7ac6f96f3cd04df6ce76b06df1ce79b05beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d045f8bf32d02dff9ceb7187c17385f0bf8e81e97f3c17791f35d00be8b9def42f0d1587b11f8e8daf062e7b3e3c4e40cbcc6f9698c0a5f43e333f896d2d80cbe65342e836f398dc9e05b01b1c9b712c615f2ad723e1aa3ec737daedc1f24d527f2619f5893f471cd91ed71d7257fdc70dd6e7d30a2753fc459035a6d70e504ef0d6ac3d819671487fc3550de0975a91ee941ef33c46ec7fdb5aebca1c8ebfabcd735409db511edef0f926dff3a8f679dc75c0bede7c9d9f6bce6ec98b79273f62aa8ebe71e5df34cc49cdd031c0c39dba5393be6ade49c1d84ba7eeed175ef44ccd96b81832167077872369fd39c2dcc91054174eed1679f8998b3478123f99cedd49c1dfb5672cede0f75fddca3cfbf1331676f078ee473b67b40af0dc6bc959cb32f81ba7eeed15ccc44ccd9078183216707759c1df35672cebe09eafab947f3821331675f0e1cc9e76c2f53ceb66bce0685f5ce2088ce3d9aa39e8839fb3070249fb387747e76ec5bc939fb69a8ebe71ead974cc49cfd802bdb75866fb8758605e0fba6f32d04dee473fb7007536ee735b70bf7810441748ed2dadd44cced475dd9e6f16370ef01f9bee37ce783efbbce7701f8bee77c1742bb18fac080f681316f25f7811f405d3f97691d7922f681af010743ce1ed29c1df35672ce3e0e75fddca37b1a2662cefe1838187276507376cc5bc939fb67a8ebe7de52579e88394bf795daeb859fbaeb85e5e0fb99f3ad00dfcf9d6f25f87ee17cabc0f74be76b05dfaf9c6f35f87eed7c39f0fdc6f9dac0f75be7cb83ef71e76b07df13ced701bedf395f27f87eef7c5de0fb83f37583ef8fced703be3f395faff3d97bf2e8deab2f3a9f3db7a4517f90ecb9a57b2ce9d8b4bf721c62377ab11bc731769317bb2922f62a86d85988415bc6dbef87f22a5e9e5c4330fafb1f146b75f2b1da6ddb5b83b1b77d35f0e418da9e851863e1c9014f5bf23ce1bdbef9e48f1b9ee3564fd32cc46a8576b533b42b03b1e8d8b44ff11ac087e3777b046347f28cf90cc4a263d37e0730920fdf4fe87d9dfa8f7d3f5c9219e165e84be13511c5a3dffe228ed5e0a73a7f9c39c2b6dcb1d5c3f3f8dedae6f998f232cc0b8a45c7a67d8a570fed691b7fc6fc5819731e23d718918158746c3f36f6f755e3afd998ce6b03f8cec198942f774caa07b6f1b84e893bd7526273bc5f6520068d6da4791efc546796fb42821ddbb6c3b8cbd0fff2a55ebfe178907c1ee773d8afc7c2d30e3c1c7d9fa9bfe6f07dff2f41b2b9d6e969d5e669d500753a40bf4e06fd8a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2984917c79e0e198e70f7f3fca1d8b8e6fd775be0beb3ac9af5be473b86649f7182ef3da5c03759ec88cd4fd21aca7fb6b83b8a6b99257bb31dd67511f9cbd16cbb98618b70e1cb57ed99258ecfc21aef5367b8f9afd1db2564fd795119a32dca7324ad38ca729dea7b8c2e3b1793ab77a848d63edafd4b548d48aca49aeede13d06bce7a5307e502e5405a3c70f7c9fe94a3cf6e8354c5a2feff262d7409dffc98c9c1bba1795fecfa17fcf93add3ed1d9b5eb30cfcdddeb1a7b9d71247ad77fc56782dd5f93f1853df5c15fc55338efb3f705c0ea0adb8f54319d7cd937f1f2eace3b797c0d3093c1ce30cd3f5460efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6ef8a126b16eae585308ed3bd0fe17a06fdfe0b1ddfaeebbcb06a242ef73a1cad392df7da5c0375be5c3552f7a5ae5c1f9c7dbf43dcb96458cf2b7a2e295e3db407d782b8becfdde1f174446841e596c46217d6f193d778641dbfddd3351fa129577fc53556d414fb6b9bc7836ba3f5c1d9f79664e138e371ef505c5e503cec4b1de0a3327e3f9ae33ce37b897f5f0fc5c3f5eb479cb6d302ae739fcf718e1b3dd0a6fee0ecfcae813aef87b1ef83ae8cf770e0bd238f463c4f5bb1756ad28fe5b7ec728575df35c0d90f7130f65a604d28761bc6ce38a338e4af81f2e7aa46ea523dd283b42676db47e837c190dd7f5d9bf7ba06a8d31bd1fefe20d9f6f7793c7d1eb33d271f813c7b14deffb9c6a4de188d9681465407af83b8eec9f3c748fffe46bc6fafceab83d72c54e70b3046c5dd3f1a75cf21d7fb58dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a0cc68ba4efd37a0c7208efd30abce32f87e313575d10ffde4275beef1ddfbf26a7d7e07d6054e747305e34ba7b16eb83b3afbff19ea9f1f87c15779f34c5c3eb1aecdb7fabed96b907eaf727c88c39812c789d40757ee39db3ee18eed511af7d22e6b5a415fd0e157e7ef1f5b33af4c26bfa13d1a1d0e7fbbcb6505ef7425ba8ce7f79d780c95fb714ae01936febe86b121a073a22da4a75fe1bfada9fe11a8fce137eeea8ab3efb79da8a5d03927eb6cde3fdfbc0185bc2ef03d7568fd4f57fe797b42ef5f781bbbcd749fc7de0ff853cab83fbd0b9c6eab5311a2d078da80e7e3788de47f0b77ca3de63b8eeed8f7b8f89fa0d4a1c9f1babc79fcd9f578bba46a03af45abc4698e998a7399dfdbafe7c21bd5f2679df307e57a215e2e277255a99f4cc816efdb08fd705e732768e2976dc6f4ee7c62176dc6f4e8f47ec262f76d338c656cd5573499a33fc2672f8fd33fccd52bb15bb2e258606785d550a18ab53c0589302c6da1430d6a58071520a1827a780714a0a18a7a680310b8ce7f2bd9d419f7cb9fa709daf62d71a189be17f97e44bfdff1dccff4ba5e8b50fc666f84c176ab12a18bb16f8398fe3b71f4afd5f2fc480ffbb607a0a1867a48071660a189b53c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89202c6f353c078410a182f4c01e3452960bc38058c4b943111c615bc8cf972192d0fc7fffc7b32ff738c81271775cf29d3774f4afe7f6bccbf4fda56eeefc6e1bd25bcff13eec9fdb61dc7bd23a5feb65db1ffb7cac4982f9791eb3e76fc1ecf5878f07b9151dfad6160cc97cbc8f5fd17fc8ede5878ba40b3ce08cd1818f3e53272dd2b57eabd9c784f7f5784660c8cf97219f1beea047942cdba4be0e901cdba23346360cc97cbc8755f7216628c85a71734eb89d08c81315f2e23d377db42cd7a4be0c1ef80f54668c6c0982f97d1f2ac61d2acaf049e35a0595f846692189127e9dfc9ee8b88c5f19dc152db4e0cc83825058c5353c088f749708c5fc5ee93e8e3d5275fae3e5ce7abd87d12189be1fb31a116f87d88bfa5c53a5e9ea2f74960ecf54c5ae0f755fe9616eb8187e3fb33598831161e626880d74d4f01e38c1430ce4c0163730a1867a58071760a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a18f1b32ac3b562d1cf2feb2778ecb8cf2a133d76dce792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d73fcca38f11891a725399e1cb61d63f50b687b7f044f86a9ed186ba380b61343da1837a480714d0a1855c7c23d88e5305a9e4d4c3c1b4be0d9043c9b99783695c0b31978b624cf13e6d4e6127888a1015eb726058c1b52c0a83aaa8ed6ec967b729bea2888310d3a2aa3322aa3329e0bc6348ce1ca988a7ccc97cb6879b626cf136ab6a5049eada019bdae8d97315f2ea3e5d9963c4fa8d9d61278b681665b23346360cc97cb6879b627cf136ab6ad049eeda0d9b608cd1818f3e5325a9e1dc9f3849a6d2f81670768b63d423306c67cb98c966767f23ca1663b4ae0d9099aed88d08c81315f2ea3e5d9953c4fa8d9ce12787681663b23346360cc97cb68797627cf136ab6ab049edda0d9ae08cd1818f3e5325a9e3dc9f3849aed2e81670f68b63b423306c67cb98c96676ff23ca1667b4ae0d90b9aed89d04c2ae39a14306e480123b38ef972192dcf3e269ebd25f0ec039e4b9878f695c07309f05c9a3c4f98539794c0430c0df0ba352960dc900246d5517594c4a83a568e8ecaa88cca581a637f0a18f55c2ba3544686cf5745bf4373c9048fdde8c56eac90d871dfa199e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1f7271f3b5fea6fccec071e8edfbc616a67ce1ef73277acbf24a89fd5ea724fab4b3cad1aa0ce65a0dfe50cfa65202e1d9bf6295ea9cc4f11c0cc143b6fc79729d07e8ab1c1d3c3c6bf82a9ed7163fd15133c76dc583fd163c78df5133db6e6b9e67925c4d63cd73caf84d89ae79ae7526263b93618b96ea7df3fb5c778aa2bd7b87d64253fd5b97452e1715aa07d8823b6f6217dafa884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3c6f80e7abc68127f07882223c8b84f1cc11c6335d18cf14613ccb84f1540be3592f8c673ceee72b856797309eedc2787a84f12c16c6b35c18cf5c613c79613c3384f1740ae3992a8c678b309e1a613c1b85f1e484f1ec11c6b34418cf3c613c3385f1ac10c69315c6532b8c6793309ed5c278960ae3d92b8c67b7309e3e613c3b84f1f40ae3e912c6335f184fbb309e66613cadc278ce13c6532f8c67ab309e3a613cab84f1ec13c6b35618cf02613cb384f13408e36914c6334918cf3a613c3b85f16c13c6d32d8c67a1309e0e613cb385f1ac14c6334d184f93309ecdc278260be3c908e0c90667ff2659169edf0fbe2aefb5f67aa0ad79e4f92b9dbf0a5e73952b57471cfb4af0d177c3af8a782dea7425b4a5df95734f6e0b75c258fdb04ff1ea81e32a213c9385f16c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e6dc278760ae359278c6792309e46613c0dc2786609e359208c67ad309e7dc2785609e3a913c6b355184fbd309ef384f1b40ae36916c6d32e8c67be309e2e613cbdc2787608e3e913c6b35b18cf5e613c4b85f1ac16c6b349184fad309eac309e15c278660ae399278c6789309e3dc27872c278360ae3a911c6b34518cf54613c9dc2786608e3c90be3992b8c67b9309ec5c2787a84f16c17c6b34b18cf7e613ceb85f1540be359268c678a309ee9c278e608e359248ca72a8287e1ff5f863c74ff1a1d9bf6f70b89cd701ec2fffb7935539bae71c7aa75c7257e8a570375ae750385bdbf0a5f4b5cfefd86f8de740d68740d535be87c64bcf3c31c3b8ff75506c01078fa04113c1cf7a332b573541e26f8ff677356ab6b3dadfc73d70075ae06fdae65d02f2ab7ffda07dc631a992d0f5d9b116b16eaad17c248be2b7879c27ebb3e18bd15ebb7d7020fc718c6d4ceb07f5de7b5697d84ee540773f53a867646f51ddabf0ece43da982dcf465726d62cd4db2884917cd7f0f284fd6b63307a2bd6bfae031e8ef187a99d61ffbade6bd3c608dda90ee6eaf50ced8cea3bb47f3d9c87b4315b9e4dae4cac59a8b7490823f9aee5e5e9c8429b692bd6bfae071e8ef187a99d61ffbac16bd3a608dda90ee6ea0d0ced8cea3bb47f039c076556e62866cb43dfe122d62cd4db2c84917cd7b1f274e4b2d066da8a8d6337000fc738cfa47b388edde8b5697384ee540773f546867646f51ddabf3122764b90ac16378d418b9b22786e1a672d285ea9cc57a7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5d96eaab3eaac3aabce4930abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac7314bd0d9f2d06f66116b16ea6d11c248beeb7979c2ef056d09466f196fbf1fca3701cf0d0cfa30b533bc87fc80d7a62d11ba531dec5f0718da19d57768ff009c87032530df984266d5b93c66cb43bf4d4fac59a8b7550823f96ee0e509c7b1adc1e8add83876007838c679a67686e3d880d7a6ad11ba531dec5f030ced8cea3bb44ff1945999e3982d0ffd8f2862cd42bd6d4218c977132b4f3efc7ee3b660f4566c1c1b009e0389f314c63106ddc371eca0d7a66d11ba531dccd5830ced8cea3bb47f10ce4329cc37a6905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff0a22d62cd4db2e84917c075879dac37587edc1e82de3edf743f920f00c24ce53587760d03d5c7738e4b5697b84ee5407fbd721867646f51dda3f04e761a233df984266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667872b136b16eaed10c248be015e9ef0770f7604a3b762f7ed1c029e830cfa30b533bc6fe7b0d7a61d11ba531dec5f8719da19d57768ff309c076556e62866cbb3d39589350bf5760a6124df415e9e701cdb198cde8a8d63878187639c676a67388e0d7a6dda19a13bd5c15c1d64686754dfa1fd41380fcaaccc51cc9667972b136b16eaed12c248be43bc3ce138b62b18bd151bc7068187639c676a67388e1df1dab42b4277aa83b97a84a19d517d87f68fc0795066658e62b63cbb5d9958b3506fb71046f21de6e5c967a1cdb4151bc78e000fc738cfd4ce701cbbd96bd3ee08dda90ee6eacd0ced8cea3bb47f339c87b4315b9e3dae4cac59a8b7470823f9067979c2feb52718bd15eb5f37030fc7f8c3d4ceb07f1df5dab4274277aa83b97a94a19d517d87f68fc279481bb3e5d9ebcac49a857a7b853092ef082f4fd8bff606a3b762fdeb28f0708c3f4ced0cfbd731af4d7b2374a73a98abc718da19d57768ff189c87b4315b9e7dae4cac59a8b74f0823f9f0fd621f134fbdc7531fa1c5448cdde8c56eac90d84d5eeca60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc39d43c730e35cfa8e62235ff4b72b13b1b8291ad0a621d656a276efd50c6f939da1609e399238c67ba309e29c2789609e3a916c6d3238c67b1309ee5c278e60ae3c90be399218ca75318cf54613c35c27872c2789608e399278c67a6309e15c278b2c2786a85f1ac16c6b354184f9f309e5e613c5dc278e60be36917c6d32c8ca75518cf79c278ea85f1d409e359258c67ad309e05c2786609e36910c6d3288c67bf309e49c278d609e3e916c6b350184f87309ed9c278560ae399268ca74918cf64613c19013cd9e0ecefa3e0f709aac147f7f7ef03dfd35c793ff8aa2262d0718e818fe673e918f6fd6a6df3d90c55f09a5b22b89e16118fe2dc12f1daf1d01d63f5c33ec5ab078e5b84f04c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e75c2782609e3d92f8ca751184f83309e59c2781608e3592b8c6795309e3a613cf5c278ce13c6d32a8ca759184fbb309ef9c278ba84f1f40ae3e913c6b35418cf6a613cb5c278b2c2785608e399298c679e309e25c27872c2786a84f14c15c6d3298c6786309ebc309eb9c278960be3592c8ca747184fb5309e65c278a608e3992e8c678e309e45c278aa2278f633f1c4fd9ec27e01b1edbc375d0bd29c58169e1f8fef29edf71869ff2830920fefd3cd31f1c4fd06454e406cabc56a28db2d0bcfe3f74cb8722ae731d27e544ee17d96ab9978e27eb763b580d8560b5a1ba07b00b2f03cde57cd9553ab3d46da8fcaa9265e9ef07f4bac0a466fc5ee35c23ec7710e99da99c3fe97e06f6844fe16f52a4fab06a8331ef715c78d07144f9995398ed9f2d0da17b1e2fbd9787c6f692c8c51efaf0c3ce1f8d81a8cde8a8d8f478187e3fd83a99de13876dc6b536b84ee540773f538433ba3fa0eed1f8f88dd1224abc5893168712282e7c4386b41f14a65de9f4266093a5b1eba579358b3506fa51046f2e57879c2f17165307a2b363e9e001e8ef70fa6768663c249af4d2b2374a73ad8bf4e32b433aaefd0fe49380fa5301f4f21b3ea5c1eb3e5a1351a62cd42bdbc1046f21d65e5c9e7b2d066da8a8d63278187639c67d23d1cc786bc36e52374a73ad8bf8618da19d577687f08ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4dd6162cd42bd76218ce43bc1ca535877680f466fc5d61d8680e764e23c85750706ddc37587535e9bda2374a73a98aba718da19d57768ff149c076556666556666556666556666556666556666556666556666556666556666596cd6c79e837e489350bf53a843092ef242f4ff8bdad8e60f4566cdde114f070accb30b5335c77b8d56b534784ee540773f556867646f51ddabf15ce83322b7314b3e5a1df1e24d62cd4eb14c248be21569ec2fa6967307a2b368edd0a3c1ce33c93eee13876da6b536784ee540773f534433ba3fa0eed9f86f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f86c49a857a5d4218c9778a95a73d5c77e80a466fc5d61d4e030fc7ba0c93eee1bac319af4d5d11ba531dec5f6718da19d57768ff0c9c8789ce7c3c85cc9a1be3c3acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc72c21372c4fb72b136b16ea750b6124dfadbc3ce1ef1e7407a3b762f7ed9c019ed30cfa30b533bc6f67d86b537784ee5407fbd730433ba3fa0eed0fc3795066658e62b63c3dae4cac59a8d72384917ca77979f25968336dc5c6b161e0e118e799da198e63b7796dea89d09dea60aedec6d0cea8be43fbb7c179481bb3e5e9756562cd42bd5e218ce4c3f7e55e269e7a8fa73e428b7315db6ad1e7cae7b9c72c3cdf078c5ce361afc748fb98e3e4ab079e3e269e468fa731428b7315db6ab116ca76cbc2f36b81912ba7fa3c46da8fcaa946e059cbc4d3e4f134456871ae625b2dd6b9f234f79885e7d70123574eadf518693f2aa79a80671d134fdc98b46e1c62c7f5aff1881d972be3115b3557cd5573d59c53f3cc39d43c730e35cfa8e6a23467b88e0ae77b2946000cb8f543193f2b705c7b32b53317f5796c9dd726fc3c86730ee7eaf386322b731c33d3bc4547d68b4dfa041e0f6dc3cc5a8ce7bc699fd7a634cc9b16633e9e4266d5b93c661bfbf6e4637764bdd8a44fe0f1d0763bb3164ced0cc7833b82688d295e03d4c13cbd83a19d19884bc7a6fd3be03c94c27c3c85ccaa7379cc36f69d89c72efc9e3cc6267d028f87b63b99b5e06967613cb82b88d698e235401dccd3bb18da9981b8746cdabf0bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9e78ecc2fc3dc6267d028f87b6a7336bc1d3cec2fcfddd41b4c614af01eae039bf9ba19d19884bc7a6fdbbe13c28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c661bfb19c9c70ebf8f83b1499fc0e3a1ed19cc5a30b5339cbfbf2788d698e235401d3ce7f730b4330371e9d8b47f0f9c076556e628661bfb9989c72eace7616cd227f078687b26b3163ced2c8c07f706d11a53bc06a883e7fc5e867666202e1d9bf6ef85f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393adbd8f7251ebb3d9cbfc7d8a44fe0f1d0761fb3163ced2cccdfdf1f446b4cf11aa00ee6e9fd0cedcc405c3a36ed53bc4a603e9e4266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b36f6b3928f1d7e9f1d63933e81c743dbb398b5606a6778ffcb0341b4c614af01ea609e3ec0d0ce0cc4a563d3fe03701e945999a3986dec07938f9dcf7ab1499fc0e3a1ed41662d98da198e070f05d11a53bc06a883e7fc21867666202e1d9bf61f82f39036663c7f93938b1ddeb74931aadca3f53ddb95abc1f71c57ae01df735db9167ccf73e53af03ddf952781ef05d01ef2bdd0955780ef45aebc0e7c2f76e5b5e07b892bf781efa5aedc0bbe97b9f230f85eeecab781ef15ae7c3bf85ee9ca7780ef55ae7c27f85eedca7781ef35aefc74f0bdd695ef06dfeb5cf919e07bbd2bdf03be37b8f233c1f74657be177c6f72e5fbc0f76657be1f7c6f71e525e07b38c2f756577e16f8dee6ca0f80efedaebc1f7cef70e529e07ba72b4f05dfdf41991edfe5cae781ef1157ae07dfbb5db9017cef71e546f0bdd795a781ef7daedc04bef7bbf274f07dc0956780ef83ae3c137c1f72e566f07dd8956781ef23ae3c1b7c1f75e539e0fb982bcf05dfc75d791ef83ee1caf3c1f749575e00be4fb9f242f07dda951781ef33aebc187c9f75653cbf7fefca0f828fc69587c047e3cab3c147e3ca73c047e3ca73c147e3caf3c047e3caf3c147e3ca0bc04779f742f051debd087c94772f061fe5dd4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f730f828efde0a3ecabbb781afc595df0ebef35df91de0bbc095df09be0b5d19c7998b5cf95de0bbd8951f011f8d85ef06df535cf93de05beacaef05df32577e1ff896bbf2fbc1b7c2953f00be95aefc41f0ad72e50f81afd5953f0cbed5aefc11f0e55cf9a3e06b73e58f812fefca1f075fbb2b7f027c1daefc49f075baf2a7c0d7e5ca9f065fb72b7f067c3daefc59f0d1fb388d33b63fdb3e483a9046d6476d6e8d680bf926435bfa8364afe928161d9bf6db8191ce417efc19f363656cf3182d4f2783669857b415fbccd4093c1d0c3c4ced0c3f3375796d6af7dad400759e02edec62686706e2d2b169bf0b62739c73d4a2d61d77a9a7450dd6716f68f6bdb3988e740c9bbff988b6f432b7858e4de352ef38c4eef662e7bcd8381ed356ac7f7503730f03b33d6e5ff2c70dfbd71a772cca298a938336ad050d926a13c6ce38a338e4af81f2bce691ba548ff4a0f72f62b7b94ce712d9fdd7757aaf6b803abd11edef0f926d7f9fc7d3e731db73d2d83cc2c1d01fc21ce8f538683f07daf5c568d70bda511d7cffcb3369d7e3f1f478b12d0f5de374818fae15881fafb35ac781db1ff7ba22b8c9d70d8c51d73a6dc93316bdd6690346f2f5004f379366feb95eeae983efcb755e1d7a6d0dd4590def8dd988bab6df2dc98cb48b3e83ff2548764caf63d00be70702d027f0340c402f6a672d03cfd460648ee0ccf0d0e9819b072f1b1c389c01b41a0f131f3311cda8021f96ab237c41307a2a04a764692a04a764ab3c59700a86eadb8f52b65934dd3078e2d8f0534f0e9e3c74faae53c38387f70cdd8cd4b51e3d92c6b50049d147dbe46064d2a63f487631a6ce8b552c7926c3e3a4e479da98da19bee94df1da54e7b5a901ead4c2735318da9981b8746cda9f12113bc18128d462ea18b4981ac133759cb5c0896ff2614fa5e771f1a4ca6b0bf6686c939fe7893688022e81e3671c9c7dce76f65ad79849c1c8c9a6d1d3cea8daab5a7b22ec0ca97de7b233a07608b2339c7646d3bea9d9194b3b43696724ed0ca49d71b4338c7646d1ce20da19433b43d812146600ed8c9f9de1b3337a1703db1781d77eaab6ef907646cecec0d919377b65653fb1d9ab117bf56daf14edd581bd2ab09f2ced2c837db7b55732f65ddabeb3da2b457b8568afe8ed15ae5da55a6f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31766950985dbfccd8e5c6ae30f65463571abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8016303c60e1a3b64ecb0b14163478cdd6ceca8b163c69e66ec96a07087ce0963278d0d193b65ec5663a78d9d090a2b667685ccae88d91530bbe26557b8ec8a965dc1b22b567685caae48d915a8fb82c20a935d29b22b437655c0ae02d8597f3bcbffdca0308b6f67ed5f101466e5ed2cbc9d75b7b3ec7656ddcea2db59733b4b6e67c5ed2cb89df5b6b3dc7656dbce62db596b3b4b6d67a5ed2cb49d75b6b3cc0f078559643b6b6c6789edacb09d05b6b3be7696f791a0308b6b676ded2cad9d95b5b3b076d6d5ceb2da59553b8b6a674ded2ca99d15b5b3a076d6d3ce72da594d3b8b69672ded2ca59d95fc9cb1478dfd83b17f34f64fc6fed9d8bf18fb57639f37f60563ff66ecdf8dfd4750c8cbff34f625635f36f615635f35f635635f37f60d63df34f62d63df36f698b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1c78d3d61ec77c67e6fec0fc6fe68ec4fc1c8ea060e227f763b34d33e303c3c78e2d470cbf050cb89db8e0f1f3b75fcae963b8e0d1f6d19ba7df0f491e34377e08bdfe5862d5a46d878faf4c05d2dc74e1e1ebcb365e8b6e196a1232d07876e3b79f80cbee8f3ee450bce8e3870f8707cb06f573d09d2ef9519f4d7ee75b440b3b378db1e2f47903f95f3a219d5e535e812f7ae439fde2f2f5cedb69c393e34dc926b3969fe0e1c37af193cdcda82cf9d31229f196e39333c707ab8e5c8e9a1132d6dad78dc6ba694d1889ae6325ed4da3cf69607ff0f1d686fac2d0a0400", + "bytecode": "0x1f8b08000000000000ffed9d77701cc795c667911856581024981324db1423b8586430813953a6242b072650a44512140925cbb2244b72ce395b4e6739e77c9673ce39e7ecba2adf3f57bef255b9ae7bb69ff1a139b3c6aee6816fb06faa1eb6e76defbc5f7ff3a667b67b7690098acb9f8d655cb9d6d8638273177a7fc0bde61fddd29ee0b6f29c9c999470d6a484b336259c7529e1ac4f0967434a3827a58473724a38a724c899013e2edea929e3cda68cf782201d79db9812ce5c4a389b52c2392d259ccd29e19c9e12ce1929e16c4909e7cc9470ce4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e29470b6a684f3c294705e9420e70ae0a431f2c7bad7c7b9d725eef562f7bad4bd2e73afcb5d1bebdcbadde64a63ab8cb579efadb6ccc6ec6079c17bafc358a7b12e63ddeebd56f75e8fb15e637dc6fa8dad31b6d6d83a63eb8d6d709a6c34b6c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd825c61e6f6cbfb14b8d5d66ec72634f307685c772a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b8d9d3076d2d8296343c64e1bbbc5d81963678d0d1bbbd5d86d9e66b71bbbc3d89dc69ee471de65ecc9c6ee36f61463f718bbd7d87dc69e6aec7e630f187bd0d8d38c3dddd8338c3dd3d8b38c3ddbd8738c3dd7d8f38c3ddfd80b8cbdd0d88b8cbdd8d84b8cbdd4d8cb8cbddcd82b8cbdd2d8ab1c0b1d08af36f61a63af35f63a63af37f690b137187ba3b137197bb3b1b718fb0f636f35f6b0b1b7197bbbb177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fb4f639f34f688b14f19fbb4b1cf18fbacb1cf19fbbcb12f18fba2b12f19fbb2b1af18fbaaa7f9d78c7dddd8378c7dd3f9bee55ebfedead231ff1df7fa5df7fa3df7fa7df7fa03affe0fbdf51f79eb3f76af3f71af3f75af3f73af3f77afbf70afbf74afbf72afbf76afbf71afbf75afbf73afbf77af7f70af7f74af7f72af765e6dc5cc62797230b20c0409f5499d837d765c9dc4f6e7edec9c50ad7b8f5e5b9dbfceadd36bc6f9ebdd7abde76f70eb0dde7626bbf5c99e3fe7d6739e7f9a5b9fe6f9a7bbf5e99ebfc5adb778fe0bddfa85e0cfbaf78a0d2bbe585fad7365c047f95903be7ae7ab055f036d0e7c939caf1e7cb47f1bc037c5f926816faaf34d065fd6f9a69096c62e70be8120a95cc91fb4db6d4c7abb6e2e22973cef21bbdd2626de69c9f31eb6db6d66e0b5f931dd6dab11f26686f3e5c0d7e27c4de0735dd0bf8e39eb9be57ccde09bed7cd3c137c7f966806faef3b5806f9ef3cd04df7ce79b05be05ce371b7c0b9d6f0ef81639df5cf02d76be79e06b75bef9e0bbd0f91680ef22e75b083eea2f1781efb1ceb7187c746dd70a3ebacebb107c74cd7791f3d97e627206e2393ff551613cea9fc1f738ea9bc1b784fa65f05d4c7d32f896426cf22d837e857ccb9d8ffa28fb5ebf2b0f04491d1385f0185e93f476cd96ed76d725bfdd700e6c7d30a2f500c459035a6d70e504ef0f69c7d8741d4371c85f07e59d5097ea911e749e2176dbefaf75e50d253ed7ef7d2e0775d646b47f2048b6fdeb3c9e751e733db49f29678f6ace8e79293b67af84ba7eeed135cf44ccd93dc0917cce767468ce8e79293b6707a1ae9f7b74dd3b1173f61ae060c8d91e9e9c2de435678be36041109d7bf4dd6722e6ec31e0483e67bb3467c7be949db3f7415d3ff7e8fbef44ccd9db8023f99cede9d16b83312f65e7ecf3a1ae9f7b3416331173f601e060c8d943dacf8e79293b675f0b75fddca371c18998b32f028ee473b68f29673b346783e29c661044e71e8d514fc49c7d083892cfd9c33a3e3bf6a5ec9cfd18d4f5738fe64b2662cebedb95ed3cc3b7dc3cc302f07ddbf916026ff2b97da49d29b7db35b78bf77a0441748ed2dcdd44cced475cd9e6f177e1de03f27d8fee4b00dff79def22f0fdc0bb6783e918e8d66360ec6d2af718f819d4f57399e69127e231f06de060c8d91ecdd9b1b7a9dc9cfd0bd4f5738fee69988839fb4be060c8d95ecdd9b1b7a9dc9cfd3bd4f5736fa92b4fc49cfd2f57b6d70b3f71d70bcbc1f753e75b01be9f39df4af0fddcf95681ef17ced706be5f3adf6af0fdcaf9f2e0fbb5f3b583ef37ce5700df6f9daf037cbf73be4ef0fddef9bac0f707e7eb06df1f9daf077c7f72be5ef0fdd9f9fa9ccfde9347f75e7dd1f9ecbe258d068264f72ddd6349dba6f595e310bbc98bdd348eb19bbdd8cd11b15731c4ce420c5a32defa009457f1f2e473c083b156271fabc3b6bd2d187bdb57034f9ea1ed598831169e3cf0b427cf139e3f0bc96f37dcc76d9ea65988d506edea6068570662d1b6699de2e5c087fd7747046367f28c850cc4a26dd37a2730920fcf27745ea7e3c79e0f97644678198ea5f09a88e2d1f39f886335f8a9ce375b46d8963bb646781fcfaded9e8f292fc3bca058b46d5aa7788dd09ef6f1672c8c9531ef3172f511198845dbf663e3f1be6afc351bd37ecd81ef3cf449854afba446601b8feb94b87d2d2536c7f92a0331a86f23cd0be0a73ab3dc0f126cdfb61dfa5d86e3af50eef51bf607c9e771218fc7f558783a8087e3d8673a5ef378deff67906cae75795ab57b5ae5a04e27e8d7c5a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b9cdfa47a2b853092af003c1ce3fce133a0dcb668fb765ee7c730af93fcbc45218f7396748fe132afcd7550e7af9991ba3f87f9747f6e10e73457f26a37a6fb2c1a8373e76239e710e3e681a3e62f5b138b5d38cc35df66ef51b3cf216bf3745d19a129c37d2aa334cd789ae27d8a2b3c1e9ba7736b47d838e6feca9d8b44ada89ce4dc1ede63c0bb5f8afd07e5424d30baffc0f34c77e2b147cf61d27c79b717bb0eeafc6f6664dfd0bda8f4bfeefc7b9e6c9d1e6fdbf49965e0eff1b63dcd7d9638eabdedb7c167a9ceff419ffaba9ae05f9a71dcff81fd72006dc56500ca386f9efc79b8388fdf51064f17f070f4334cd71b793c06929ec7eff1b48aba8ea13adda05f0f837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff39c9a91b8dcf37034e7b4dc6b731dd4f946cd48dd17b8726370eefd0e71fb92613eafe4bea4788dd01e9c0be2fa3d77a7c7d319a105955b138b5d9cc74f5ee39179fc0e4fd74284a65cc72bceb1a2a678bcb67b3c3837da189c7b6f4916b6331ef70ec5e505c5c363a9137c54c6df4773ec673c97f8f7f5503c9cbf7ed8693b2de0daf7853c67bfd10b6d1a08cecdef3aa8f32ee8fbdee3ca780f07de3bf248c4fbb4949aa726fd589e65972fcefbae01ce018883b1d7026b42b1db3176c619c5217f1d943f59335297ea911ea435b1db63849e0986ecfee7dabdcfe5a04e5f44fb078264dbdfeff1f47bcc769fbc1ff2ec1138ff73f5497d311a2d038da80e5e0771dd93e7f791fefd8d78df5e835707af59a8ce17a18f8abb7f34ea9e43aef358dc3d8751d7c65dc0e8b7d1bfcfb3daefd3fa21f41749dfa7f543c821bc4f2bf0b6bf1cb64f5c0d41fcb985eafcd4dbbe7f4d4e9fc1fbc0a8ce2fa0bf6872f72c3606e75e7fe33d53e3f1fd2aee3e698a87d735786cffbbb65be65ea83f902033e604b2e07502d5f993b7cf7a62b857477cf6af319f25ade83954f8fdc5d7cfead0079f19484487e231dfefb585f2ba0fda4275fedbbb064cfebaa5780d987c5b475f93503fd019d156aaf33f70acfd1daef1683fe1f78e86da73dfa7a5d43520e967db3cdecf07c6d8129e0f5c5f3b52d77fce2f695deef381bbbdcf497c3ef03f20cf1ae03e74aebe7a6d8c46cb4123aa83bf0da2f3083ecb37ea1cc3756f7fdc3926ea1994d83f37d58e3f9b3fae16758d4075e8b3788dd0e298a7399dfdbafe78219d2f93bc6f187f2bd10671f1b7126d4c7ae641b70158c7eb82f3193bcf143bee99d3f971881df7cce9f188ddecc56e1ec7d8aab96a2e497386672287bf3fc36796daa5d4752931e4e073352960ac4d01635d0a18eb53c0d89002c64929609c9c02c62929609c9a02c62c309ecf733b833e854af5e1da5fa5ae353036c3ff2e2994fbff3b98ff974ac96b1f8ccdf09d2ed4625530762df07b1ec7b31fcafd5f2fc480ffbb607a0a1867a480b125058c3353c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89a02c60b53c078510a181f9302c6c7a680f17129605ca28c8930aee0652c54ca687938fee7dfa3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e697ba5cf8dc37b4b78ff27dca37bb61dc7bd23e53edbaed4ff5b65622c54cac8751f3bfe8e672c3cf8bbc8a8dfd63030162a65e4fafd0bfe466f2c3cdda0595784660c8c854a19b9ee952bf75e4ebca7bf3b423306c642a58c785f75823ca1663d65f0f482663d119a3130162a65e4ba2f390b31c6c2d3079af54668c6c058a89491e9b76da1667d65f0e06fc0fa223463602c54ca6879d63069d65f06cf1ad0ac3f4233498cc893f473b2fb236271fc66b0dcb61303324e4901e3d41430e27d121cfd57a9fb24fa79f52954aa0fd7fe2a759f04c666f87d4ca805fe1ee2df69b18e97a7e47d12187b3d9316f87b957fa7c57ae0e1f8fd4c16628c85871872f0b9e929609c9102c6961430ce4c01e3ac1430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01237e5765b8562cf9fd65fd048f1df75d65a2c78efb5e32d1636b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae79262a7618c5f19271e23f2b426c793c7b663ac01016d1f88e0c930b51d636d14d07662481be3861430ae4901a3ea58bc07b11246cbb389896763193c9b80673313cfa632783603cf96e479c29cda5c060f31e4e0736b52c0b821058caaa3ea28895175ac1e1d955119955119cf07631afa70654c453e162a65b43c5b93e70935db5206cf56d08c3ed7cecb58a894d1f26c4b9e27d46c6b193cdb40b3ad119a3130162a65b43cdb93e70935db5606cf76d06c5b84660c8c854a192dcf8ee47942cdb697c1b30334db1ea1190363a15246cbb333799e50b31d65f0ec04cd764468c6c058a894d1f2ec4a9e27d46c67193cbb40b39d119a3130162a65b43cbb93e70935db5506cf6ed06c5784660c8c854a192dcf9ee47942cd7697c1b30734db1da1190363a15246cbb337799e50b33d65f0ec05cdf644682695714d0a1837a4809159c742a58c96671f13cfde3278f601cf254c3cfbcae0b904781e9f3c4f98539794c1430c39f8dc9a14306e4801a3eaa83a4a62541dab4747655446652c8f7120058cbaaf95512a23c3f7ab92bfa1b96482c76ef262375549ecb8dfd04cf4d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e6b9a4d8fb938f5d28f71933fb8187e399374cedccdbed5eeab6f5cf04f5b35a5de6697589a7550eea5c0afa5dc6a05f06e2d2b6699de295cb7cb10066a6d805dbbf4c81f6538c0d9e1e36fee54c6d8febeb2f9fe0b1e3fafa891e3baeaf9fe8b135cf35cfab21b6e6b9e67935c4d63cd73c97121bcbf5c1c8753b3dffd46ee309ae5ce7d69195fc54e7f1938aafd3023d863862eb31a4e78a6a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9ecbcbf31cbc5f330e3c81c71394e059248c678e309ee9c278a608e359268ca75618cf7a613ce3713f5f393cbb84f16c17c6d32b8c67b1309ee5c278e60ae32908e399218ca74b18cf54613c5b84f1d409e3d9288c272f8c678f309e25c278e609e36911c6b342184f56184fbd309e4dc278560be3592a8c67af309eddc278fa85f1ec10c6d3278ca75b18cf7c613c1dc278660ae36913c67381309e46613c5b85f13408e359258c679f309eb5c2781608e399258c27278ca74918cf24613ceb84f1ec14c6b34d184f8f309e85c2783a85f1cc16c6b35218cf34613ccdc278360be3992c8c272380271b9cfb4cb22cbcbf1f7c35de67edf540f3cc91f7af70fe1af8cc95ae5c1bb1ed2bc047bf0dbf32e2b3a8d315d0960157ce3fba25d409630dc03ac56b048e2b85f04c16c6b359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278b609e3d9298c679d309e49c2789a84f1e484f1cc12c6b34018cf5a613cfb84f1ac12c6d3208c67ab309e46613c1708e36913c63353184f87309ef9c278ba85f1f409e3d9218ca75f18cf6e613c7b85f12c15c6b35a18cf26613cf5c278b2c2785608e36911c6334f18cf12613c7b84f1e485f16c14c653278c678b309ea9c278ba84f1cc10c65310c6335718cf72613c8b85f1f40ae3d92e8c6797309efdc278d60be3a915c6b34c18cf14613cd385f1cc11c6b348184f4d040fc3ffbf0c79e8fe35da36adef17129b613f84fff7f32aa6365dedb655efb64bfc14af0eea5ce33a0a7b7f157e96b8fcfb0df1dc7435687435535b687f64bcfdc31d1befab0c8021f0f409227838ee47656ae7a83c4cf0ffcfe6ad56d7785af9fb2e0775ae02fdae61d02f2ab7ff750c000f5de7106b16eaad17c248becb9979b2d0665a4a1d03d7000fc731c9d4ce3057aff5dab43e4277aa83b97a2d433ba38e1d5abf167836ba32b166a1de46218ce4bb9a99270b6da6a554ae5e0b3c1cc70e533bc35cbdce6bd3c608dda90ee6ea750ced8c3a7668fd3ae0d9e4cac49a857a9b843092ef1a5e9ece2cb4999652b97a1df0701c3b4ced0c73f57aaf4d9b2274a73a98abd733b433ead8a1f5eb613f28b33247315b1efa9d0eb166a1de66218ce4bb9695a7339f8536d352aa1fbb1e7838fa7926ddc37eec06af4d9b2374a73a98ab3730b433ead8a1f51b2262b706c96a71e318b4b83182e7c671d682e295cb7c550a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7f161569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d5b93266cb43cf4522d62cd4db2284917cd7f1f284bf0bda128c5e32defa00946f049eeb19f4616a67780ff901af4d5b2274a73a787c1d606867d4b143eb07603f1c2883f9861432abce95315b1e7afe38b166a1de56218ce4bb9e9727ecc7b606a39752fdd801e0e1e8e799da19f66307bd366d8dd09deae0f17590a19d51c70ead533c6556e63866cb43ff078858b3506f9b1046f2ddc8ca53087fdfb82d18bd94eac70e02cf81c4798afd1883ee613f76c86bd3b608dda90ee6ea218676461d3bb47e08f64339cc37a4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9f2d0ff8321d62cd4db2e84917c0758793ac27987edc1e825e3ad0f40f910f01c4c9ca738efc0a07b38ef70d86bd3f608dda90e1e5f8719da1975ecd0fa61d80f139df98614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5c9958b3506f871046f21de4e5099f7bb02318bd94ba6fe730f01c62d087a99de17d3b47bc36ed88d09deae0f17584a19d51c70ead1f81fda0ccca1cc56c7976ba32b166a1de4e218ce43bc4cb13f6633b83d14ba97eec08f070f4f34ced0cfbb141af4d3b2374a73a98ab830ced8c3a76687d10f683322b7314b3e5d9e5cac49a857abb843092ef302f4fd88fed0a462fa5fab141e0e1e8e799da19f66347bd36ed8ad09dea60ae1e656867d4b143eb47613f28b33247315b9eddae4cac59a8b75b0823f98e30f364a1cdb494eac78e020f473fcfd4ceb01fbbc96bd3ee08dda90ee6ea4d0ced8c3a7668fd26e0d9e3cac49a857a7b8430926f9099270b6da6a554aede043c1cc70e533bc35c3de6b5694f84ee540773f518433ba38e1d5a3f063c7b5d9958b3506faf1046f21d65e6c9429b692995abc78087e3d8616a6798abc7bd36ed8dd09dea60ae1e676867d4b143ebc781679f2b136b16eaed13c2483eecc7f631f1347a3c8d115a4cc4d84d5eeca62a89ddecc56eae92d89ae79ae7d5105bf35cf3bc1a626b9e6b9e5743ec6acd35d5bc3a35cf9c47cd33e751f38c6a2e52f37f2617bb2b178c2c35108b617cae7d2c638ec8b34818cf1c613cd385f14c11c6b34c184fad309e5e613c8b85f12c17c63357184f4118cf0c613c5dc278a60ae3a913c69317c6b34418cf3c613c2dc2785608e3c90ae3a917c6b35a18cf52613cfdc278fa84f1740be3992f8ca74318cf4c613c6dc2782e10c6d3288ca74118cf2a613c6b85f12c10c6334b184f4e184f93309efdc2782609e359278ca74718cf42613c9dc278660be359298c679a309e66613c9385f16404f06483737fdb81bf27a8051fdddfbf0f7c4f74e5fde0ab898841db390e3e1acfa56dd8f3d58299e732d4c0676e8ee07a62443c8a7373c467c743778c3500eb14af11386e16c23359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278d609e399248c67bf309e26613c39613cb384f12c10c6b35618cf2a613c0dc2781a85f15c208ca74d18cf4c613c1dc278e60be3e916c6d3278ca75f18cf52613cab85f1d40be3c90ae359218ca74518cf3c613c4b84f1e485f1d409e3992a8ca74b18cf0c613c05613c7385f12c17c6b358184faf309e5a613ccb84f14c11c6335d18cf1c613c8b84f1d444f0ec67e2897b9ec27e01b1edb8375d0bd2985816de1f8fdf29edf71869fd1830920fefd3cd33f1c43d83222f20b6d5623594ed9285f7f177265c3995f718693d2aa7f03ecbd54c3c71cfed582d20b6d582e606e81e802cbc8ff75573e5d46a8f91d6a372aa999727fcff01ab82d14ba97b8df098e3d8874cedcce3f197e03334229f91bccad32a0775c6e3bee2b8fe80e229b332c7315b1e9afb22563c9f8dc7ef96c6c218757e65e009fbc7b660f452aa7f3c063c1ce70fa67686fdd809af4d6d11ba531dccd5130ced8c3a7668fd4444ecd620592d4e8e418b93113c27c7590b8a572ef3fe14324bd0d9f2d0bd9ac49a857a2b8530922fcfcb13f68f2b83d14ba9fef124f0709c3f98da19f609a7bc36ad8cd09deae0f1758aa19d51c70ead9f82fd500ef3891432abce95315b1e9aa321d62cd42b086124df31569e423e0b6da6a5543f760a7838fa7926ddc37e6cc86b53214277aa83c7d710433ba38e1d5a1f82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0ffd769858b350af430823f94eb2f214e71d3a82d14ba9798721e03995384f71de8141f770dee1b4d7a68e08dda90ee6ea698676461d3bb47e1af683322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf40c7962cd42bd4e218ce43bc5cb13fe6eab3318bd949a77380d3c1cf3324ced0ce71d6ef1dad419a13bd5c15cbd85a19d51c70eaddf02fb419995398ad9f2d0b30789350bf5ba8430926f8895a7387fda158c5e4af563b7000f473fcfa47bd88f9df1dad415a13bd5c15c3dc3d0cea86387d6cfc07e2887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1e9d2d0ffd4f4362cd42bd6e218ce43bcdcad311ce3b7407a39752f30e678087635e8649f770dee1acd7a6ee08dda90e1e5f6719da1975ecd0fa59d80f139df9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426e589e1e5726d62cd4eb11c248be5b7879c2e71ef404a39752f7ed9c059e330cfa30b533bc6f67d86b534f84ee54078faf618676461d3bb43e0cfb419995398ad9f2f4ba32b166a15eaf1046f29d61e6c9429b6929d58f0d030f473fcfd4ceb01fbbd56b536f84ee540773f5568676461d3bb47e2bf0f4b932b166a15e9f1046f2e139ae8f89a7d1e3698cd0e27cc5b65af4bbf205ee350beff7032357dfd2e731d23ae638f91a81a79f89a7c9e3698ad0e27cc5b65aac85b25db2f0fe5a60e4caa97e8f91d6a372aa0978d632f1347b3ccd115a9cafd8568b75ae3ccdbd66e1fd75c0c895536b3d465a8fcaa966e059c7c413d727ad1b87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c478563a7142300065c06a08cdf1538ae3d99da998ffa3eb6ce6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879661662dc6730cb2df6b93b431c872994fa4905975ae8cd9c6be2df9d89d592f36e913783cb4dcc6ac05533bc3fee0f6205a638a97833a98a7b733b433037169dbb47e3bec8772984fa4905975ae8cd9c6be23f1d8c567b3636cd227f07868b983590b9e7616fb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01f945999955999955999955999955999955999955999955999955999955999955936b38dfda4c46317c7ef3136e913783cb43c89590b9e7616c7efef0aa235a67839a883fbfc2e867666202e6d9bd6ef82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271f3bfc3d0ec6267d028f879627336bc1d4ce70fcfeee205a638a97833ab8cfef66686706e2d2b669fd6ed80fcaaccc51cc36f653128f5d9ccfc3d8a44fe0f1d0f214662d78da59ec0fee09a235a67839a883fbfc1e867666202e6d9bd6ef81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c3d3adbd8f7261ebb231cbfc7d8a44fe0f1d0722fb3163ced2c8edfdf17446b4cf1725007f3f43e867666202e6d9bd6295e35309f4821b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80d1bfba9c9c70e7fcf8eb1499fc0e3a1e5a9cc5a30b533bcffe5fe205a638a97833a98a7f733b433037169dbb47e3fec076556e628661bfb0186d8592f36e913783cb43cc0ac05533bc3fee0c1205a638a97833ab8cf1f64686706e2d2b669fd41888d7a27143bbc079262d4b857eb7b9a2bd782efe9ae5c07be67b8723df89ee9ca0de07b962b4f02dfb3a13de47b8e2baf00df735d791df89ee7ca6bc1f77c57ee07df0b5cb90f7c2f74e561f0bdc8956f05df8b5df936f0bdc4956f07df4b5df90ef0bdcc95ef04dfcb5df949e07b852bdf05be57baf293c1f72a57be1b7caf76e5a780ef35ae7c0ff85eebcaf782ef75ae7c1ff85eefca4bc0f75084ef0daefc54f0bdd195ef07df9b5c793ff8deecca53c0f716579e0abeff8032bdbed5952f00dfc3aedc08beb7b9720e7c6f77e526f0bdc395a781ef9daedc0cbe77b9f274f0bddb956780ef3daedc02bef7baf24cf0bdcf956781effdae3c1b7c1f70e539e0fba02bcf05df875c791ef83eeccaf3c1f711575e00be8fbaf242f07dcc951781efe3aebc187c9f7065dcbfffe9ca0f808ffa9507c147fdcad3c047fdcad3c147fdca33c047fdca33c147fdcab3c047fdcab3c14779f71cf051de3d177c9477cf031fe5ddf3c14779f702f051debd107c94772f021fe5dd8bc14779f712f051debd147c94772f031fe5ddcbc14779f70af051debd127c9477af021fe5ddabc14779f71af051debd167c9477af031fe5ddebc14779f710f828efde003ecabb3782afd595df04be0b5df9cde0bbc895df02bec7b832f6338f75e5b782ef71aefc30f8a82f7c1bf82e76e5b7836fa92bbf037ccb5cf99de05beecaef02df0a577e37f856baf27bc0b7ca95df0bbe36577e1ff856bbf2fbc19777e50f80afdd953f08be822b7f087c1daefc61f075baf247c0d7e5ca1f055fb72b7f0c7c3daefc71f0f5baf227c047e771ea67ecf16c8f41d28134b23e6a735b445bc83719da3210247b4d47b168dbb4de018cb40f0ae3cf58182b63bbc76879ba1834c3bca2a5d4f78f2ee0e964e0616a67f8fda3db6b5387d7a61cd4b918dad9cdd0ce0cc4a56dd37a37c4e6d8e7a845bddbee524f8b3aa8f3077792b3e7ce523ad2366cfe1622dad2c7dc16da36f54b7de310bbc78b9df762637f4c4ba9e3ab07987b1998ed76fb93df6e787cad71dba29ca2387968d35ad020a93661ec8c338a43fe3a28ffa365a42ed5233de8fc45ec3697695f22bbffb92eef7339a8d317d1fe8120d9f6f77b3cfd1eb3dd277f6b19e160381ec21ce8f338683d0fdaf5c768d707da511d3cff1598b4ebf5787abdd89687ae71bac147d70ac48fd7596de3c0edf77bdd11dce4eb01c6a86b9df6e4194b5eebb40323f97a81a78749337f5f2ff5f4c1f3728357873e5b07759adc97bd69c1e8ef1f54d71e774b3223eda2efe0ff0c92edd31b18f4c2f18100f4093c0d03d08bda59cfc03335181923383b3c74e6e04d83970e1e3c9201b43a0f135f3311cda8011f966b237c41307a2804876469280487646b3c59700886eadbaf52b65934dc3078f2f8f0134e0d9e3a7ce6ced3c38347f60cdd84d4f51e3d92c6b50049d147cbe46064d066204836791abc58a5926732bc4e62e0616a6778d29be2b5a9c16b530eead4c37b5318da9981b8b46d5ac70160f26176d2fb386150e3b505b3780abcfafb36d10651c0c7c0f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b0d8aa35e1701cf1781d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd5913d23da33a1fd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d99596f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31f6f8a038a27ca9b1cb8c5d6eec09c6ae3076a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b83e21d1e278d9d323664ecb4b15b8c9d31763628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee0d8ab32a7676c4ce86d891703bf26d47baedc8f63382e2c8b51da97e76501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1414474eed48a91d19b523a176e4d38e74da91cd8783e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee93c61e31f629639f36f619639f35f639639f37f685a098935f32f665635f31f655635f33f67563df30f64d63df32f66d63df31f65d63df33f67d633f30f643633f32f663633f31f653633f33f67363bf30f64b63bf32f66b63bf31f65b63bf33f67b637f30f647637f32f6e76064d41e3b8abfbb151a413e383c3c78f2f470ebf050ebc95b4f0c1f3f7de2ced6db8f0f1f6b1dba6df0ccd11343b7e387dfeaba261a1edf78e6ccc13b5b8f9f3a327847ebd0adc3ad43475b0f0ddd7aeac859fcd017dc87169c1bf1e09123f1c17e50f328487f5261d03fbacfd1c4c3ced26dfb4b2582fcad920fcda8adac4197b8330b7d2bbdac7815d77af6c4d0706bbef594f97bf084f9cce091b6567cefac11f9ec70ebd9e18367865b8f9e193ad9dade86dbbd7a4a058df87d4b051fcacd1c7bcb83ff079bac954d69010400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047ce1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c6459bf87c9726c0877c974cd9e4f9f1eb609376ff35b049bf8057c126c7a657c026cfa45e069b3cb37a096ca375fe63b0c9b363ecb32fcfffb781ad4ae7b1aff8709ddf0236e94b857d94a53fdc66b0499f46ec1b2bfd5237824dfa16639f4ce91fbe1e6cd2c71ffb02ca7b1a6bc126efda601f34795f6a35d8f6ea3cf67d92efd0ac04db749d5f01b63fe8fc72b03da4f3b782edf73aff15d87ea7f38bc0f6a0cebf05b6dfeafc12b03da0f32f82ed373aff02d8eed7f9e7c1769fcee3bb6cbfd6f95d60fb4ce7f11daa693abf136cbfd2797c77e75e9ddf0eb65feafc73609baaf3cf826d8ace2f04db2f747e01d87eaef3f3c13659e7e781ed673a3f176c93747e0ed87eaaf3b3c1365ee76781ed273a3f136ce3747e06d8c6eafc3360fbb1ce3f0db61fe9fc9760bb5be71783ad85ce2f059b8c1989fd540a75fe6db0b5d279ec7f24dff79f08b6c3747e02d8dae87c2dd8e4db70a3c126e341d7802da1f3d5603b42e7abc026e767c3c126e39f0c039b9c4b0d055b7b9d1f023639ef190c3619cf7210d8e41ba47dc176b4ce57824dbead5f01b663757e3fd864ccb137c126dfaddb0b36198bf911b0c9f7aaa783ed249dff03d8641c9687c0768aceff1e6ca7eafcefc026dff07c106c253aff5bb075d4f907c076baceff066c3246d6fd603b53e7ef039b8c1dfc6bb0c9f79e3f035b279d9f06b67374fe576093b144ee059b8c0ffa4bb075d6f9a96093ef704f01db053aff0bb0c9787f3f079b7c637832d8645cb79f81adabce4f025b99ceff146cdd747e3cd8ca75fe2760ebaef3e3c0d643e7c782ada7ceff186cbd74fe4760ebadf3d2cea8fd59ede7fbf47c3288efbc4cf9fb30a83f35746d200cc813e7b97631f0a0af3db1d7bd2c755e2ffb7d0bbd5e89a13de07b77ecbed3d7141fe87515eaf5ee367c1742997374e3a09693637e4bbddc5e6339bc8f25eb96652e04fb2e63dded757d3f7054dfdd069370a30e52e67ccda48e8d3fd0f936b04c8c6ca9eb6389b50034c42909796170a35559299ef73686e703e0d9133b4ffa7add454ce0be15f7f5ba791fd78cb56228b31bf4dbe5403fdcd765dd322ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f3332b9e7d3a8fcf95a5dc3e1246b1ed011e17f7f9f139acac5f3dd7d9755a9ddf3db1fbadff7caf955e6fa951e74228f3353c73daabf345f07fd96e51dbd2c173c206b7a5f82b82fae0b3a07d8e78f6183c7b2c5a48be2436df6523dd685c56aafaada867ec7b0d5df7593475b5bfeed1eb2a3034c5fdf54383079f8d1601ef47fa3701ebf908eae0601f6f302ec41fee4b7bc026f90f81d1c576c66389b407f23c1c9f4d4b995f19cfc5e3dff665a52edb8df7a14ec9e0c0f82e8432bf83b6ef739dc7be21fb40b77f58fe2f5343cfa9453f55e71df1d739b57db7036712fca0eff7803526dff5dea129d049fc88bd10f27f87fe1c524ef410ad851dc72b477673b90f8de58aa1cc4e4bfd9341bcf5df61f0ec3098d536f912e2ec1f70fc77d526ed8cd0e842d048caec018df63ae2d963f00887f8536564fbb736cac8b28550e67f411ba5ea22edbcd413fbb6e031c0d5714c7cc9ba65de766efc01309a7554f131f0d83ade3db1f3e656ffafc34ad2bfd8aec7d5ff4bd6dd5e2f2b1c81b1fe5258bf70b50ea28f2dffb37d4bead6efb27fd95ea3cec2823a4b997625e95f156797e97c26e7fa87eaba2dea5c7fa7039e4450ffda5b4d0d1ddff118f3be031e47f52cb51dbb7619752a86329da09e0ece631a7c177807f876b1cd510b3987da6d685108653a96a47fa5ed88d211af553fc84a5dcaace783a596ba48994e2575756903f638995c6eb7f7a04e6abd7b2c759532e797d4e9d245e713b09df0be495fcbff656aa83dc0b178b6c65fe7d4f6dd029c49f083bedf05d6987cd7fb16889cef8b1fb11742beb2a4aeac94133d446b6157fb88bcf387ece672bb8de58aa1cc364bfd9341bcf5df6af06c3598d536e95a5297973872d96e6e8bd0a81434923278ff588eedf8de9dedb8bfc71177d4717f0f309aed269ebbb864db6bb099f7506de7835206cfc9a4ccd525e95fd5ce262c65cd7bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7401fb1e9d179dbb18da1542994125e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1f434aeab871ecc43dfab7086c9fe85f47d769e5b67b86c261bb6738bca48e1d9715ae8f2d7531af915b0407de53ffda288bf7dd1a5acecc9be3502a7d3f31cad9fce0354f6cef6a742d2d45a61681fd7ec187067b4170e0989bb21f60cc99f751ba18ebc1fb28b525e95f6993ccb26adbfffbd175fac87614edb03dc198fc1018933a5ffacda6aeb6facbbcf8538c1f197570d376a5df57cae43ef05ee071d1b63b6aa34bf1181bdff7297a57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0dcac800708c5506009b2d6c6f00000028481f8b08000000000000ffed9d77741cc791c667911856000892600e50a219c1c5228309cc99122559391024419116495024942ccb922cc939e76c399de59cf35917edbbf3390739e72839dd3ff77cefee3dbfeb9eed323e3467d6d8d5145883ad79afb03db5bd53bffea6ba77b67b7691090adb9f8c655cb9dad885c1d91b3ddfef1e734f6e6b4bf058394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c9352c23939259c5312e4b46c55c1e82d69dea90cba26cd984d99a6e7a540d3fa9469da90024d1b83748c51d352c2d99412cee929e19c9112ce9929e16c4e09e7ac9470ce4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09674b4a38cf4f09e70529e1bc30259c17a584f3e204395700e712f7f814f7b8d43d2e738fcbdd23bd66a57b5ce5da58e3f65b8dadb66cc6dabce7f2c6da8d7518ebf49eeb32d66dacc758af7baec53dd7676c8db1b5c6d6195b6f6c83d361a3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e3176a9b1fdc62e3376b9b12b8c3dd5d895c6ae3276b5b16b3c966b8d5d67ec7a633718bbd1d84dc60e181b3076d0d82163878d0d1a3b62ec6663478d1d33f63463b7183b6eec84b193c6868c9d3276abb1d3c6ce181b36769bb1db8ddd61ec4e6377799a3dddd8ddc69e61ec1e8ff399c6ee35769fb1fb8d3dcbd803c61e34f690b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1571b7b8db1d71a7b9db1d71b7b83b1371a7b9363a18ef066636f31f6b0b1b71a7b9bb1b71b7b87b1771afb3b63ef32f688b1771b7b8fb1f71a7b9fb1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb7b639f33f6a8b17f30f68fc6fec9d83f1bfb1763ff6aecf3c6be60ecdf8cfdbbb1ff30f64563ff69ec4bc6beec69fe15635f35f635635f77be6fb8c76fbaba342ff62d63df76e5c7dce377dce377dde3f7bcd77cdfd80f3cdf0f8dfdc8f3fdd8d84f5cf9a7eef167eef1e7eef117eef197eef157eef1d7eef137eef1b7eef171f7f8847bfc9d7bfcbd7bfc837bfca37bb46baa973617ca938391ad3f48688cea3892b36b2a24fe9260f466b5a876cfd1638bf3d7b87d7a24ed6add7eade7af73fb75de7126bbfdc99ebfc9ed3779fe196e7f86e76f76fbcd9e7fb6db9fedf92f72fb17813f1bc09cabf35b5fb57365c047f95a05be5ae7ab065f1d1d0e7c939caf167c747eebc037c5f926816faaf34d065fd6f9a69096c6ce73befe20a95cc90dd8e3d6277d5cb70ed5903cef217bdc4626de69c9f30edae33631f0dafc98ee8e350df26686f335816fa6f34d079f1b82fedae7ac6f96f3cd04df6ce76b06df1ce79b05beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d045f8bf32d02dff9ceb7187c17385f0bf8e81e97f3c17791f35d00be8b9def42f0d1587b11f8e8daf062e7b3e3c4e40cbcc6f9698c0a5f43e333f896d2d80cbe65342e836f398dc9e05b01b1c9b712c615f2ad723e1aa3ec737daedc1f24d527f2619f5893f471cd91ed71d7257fdc70dd6e7d30a2753fc459035a6d70e504ef0d6ac3d819671487fc3550de0975a91ee941ef33c46ec7fdb5aebca1c8ebfabcd735409db511edef0f926dff3a8f679dc75c0bede7c9d9f6bce6ec98b79273f62aa8ebe71e5df34cc49cdd031c0c39dba5393be6ade49c1d84ba7eeed175ef44ccd96b81832167077872369fd39c2dcc91054174eed1679f8998b3478123f99cedd49c1dfb5672cede0f75fddca3cfbf1331676f078ee473b67b40af0dc6bc959cb32f81ba7eeed15ccc44ccd9078183216707759c1df35672cebe09eafab947f3821331675f0e1cc9e76c2f53ceb66bce0685f5ce2088ce3d9aa39e8839fb3070249fb387747e76ec5bc939fb69a8ebe71ead974cc49cfd802bdb75866fb8758605e0fba6f32d04dee473fb7007536ee735b70bf7810441748ed2dadd44cced475dd9e6f16370ef01f9bee37ce783efbbce7701f8bee77c1742bb18fac080f681316f25f7811f405d3f97691d7922f681af010743ce1ed29c1df35672ce3e0e75fddca37b1a2662cefe1838187276507376cc5bc939fb67a8ebe7de52579e88394bf795daeb859fbaeb85e5e0fb99f3ad00dfcf9d6f25f87ee17cabc0f74be76b05dfaf9c6f35f87eed7c39f0fdc6f9dac0f75be7cb83ef71e76b07df13ced701bedf395f27f87eef7c5de0fb83f37583ef8fced703be3f395faff3d97bf2e8deab2f3a9f3db7a4517f90ecb9a57b2ce9d8b4bf721c62377ab11bc731769317bb2922f62a86d85988415bc6dbef87f22a5e9e5c4330fafb1f146b75f2b1da6ddb5b83b1b77d35f0e418da9e851863e1c9014f5bf23ce1bdbef9e48f1b9ee3564fd32cc46a8576b533b42b03b1e8d8b44ff11ac087e3777b046347f28cf90cc4a263d37e0730920fdf4fe87d9dfa8f7d3f5c9219e165e84be13511c5a3dffe228ed5e0a73a7f9c39c2b6dcb1d5c3f3f8dedae6f998f232cc0b8a45c7a67d8a570fed691b7fc6fc5819731e23d718918158746c3f36f6f755e3afd998ce6b03f8cec198942f774caa07b6f1b84e893bd7526273bc5f6520068d6da4791efc546796fb42821ddbb6c3b8cbd0fff2a55ebfe178907c1ee773d8afc7c2d30e3c1c7d9fa9bfe6f07dff2f41b2b9d6e969d5e669d500753a40bf4e06fd8a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2984917c79e0e198e70f7f3fca1d8b8e6fd775be0beb3ac9af5be473b86649f7182ef3da5c03759ec88cd4fd21aca7fb6b83b8a6b99257bb31dd67511f9cbd16cbb98618b70e1cb57ed99258ecfc21aef5367b8f9afd1db2564fd795119a32dca7324ad38ca729dea7b8c2e3b1793ab77a848d63edafd4b548d48aca49aeede13d06bce7a5307e502e5405a3c70f7c9fe94a3cf6e8354c5a2feff262d7409dffc98c9c1bba1795fecfa17fcf93add3ed1d9b5eb30cfcdddeb1a7b9d71247ad77fc56782dd5f93f1853df5c15fc55338efb3f705c0ea0adb8f54319d7cd937f1f2eace3b797c0d3093c1ce30cd3f5460efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6ef8a126b16eae585308ed3bd0fe17a06fdfe0b1ddfaeebbcb06a242ef73a1cad392df7da5c0375be5c3552f7a5ae5c1f9c7dbf43dcb96458cf2b7a2e295e3db407d782b8becfdde1f174446841e596c46217d6f193d778641dbfddd3351fa129577fc53556d414fb6b9bc7836ba3f5c1d9f79664e138e371ef505c5e503cec4b1de0a3327e3f9ae33ce37b897f5f0fc5c3f5eb479cb6d302ae739fcf718e1b3dd0a6fee0ecfcae813aef87b1ef83ae8cf770e0bd238f463c4f5bb1756ad28fe5b7ec728575df35c0d90f7130f65a604d28761bc6ce38a338e4af81f2e7aa46ea523dd283b42676db47e837c190dd7f5d9bf7ba06a8d31bd1fefe20d9f6f7793c7d1eb33d271f813c7b14deffb9c6a4de188d9681465407af83b8eec9f3c748fffe46bc6fafceab83d72c54e70b3046c5dd3f1a75cf21d7fb58dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a0cc68ba4efd37a0c7208efd30abce32f87e313575d10ffde4275beef1ddfbf26a7d7e07d6054e747305e34ba7b16eb83b3afbff19ea9f1f87c15779f34c5c3eb1aecdb7fabed96b907eaf727c88c39812c789d40757ee39db3ee18eed511af7d22e6b5a415fd0e157e7ef1f5b33af4c26bfa13d1a1d0e7fbbcb6505ef7425ba8ce7f79d780c95fb714ae01936febe86b121a073a22da4a75fe1bfada9fe11a8fce137eeea8ab3efb79da8a5d03927eb6cde3fdfbc0185bc2ef03d7568fd4f57fe797b42ef5f781bbbcd749fc7de0ff853cab83fbd0b9c6eab5311a2d078da80e7e3788de47f0b77ca3de63b8eeed8f7b8f89fa0d4a1c9f1babc79fcd9f578bba46a03af45abc4698e998a7399dfdbafe7c21bd5f2679df307e57a215e2e277255a99f4cc816efdb08fd705e732768e2976dc6f4ee7c62176dc6f4e8f47ec262f76d338c656cd5573499a33fc2672f8fd33fccd52bb15bb2e258606785d550a18ab53c0589302c6da1430d6a58071520a1827a780714a0a18a7a680310b8ce7f2bd9d419f7cb9fa709daf62d71a189be17f97e44bfdff1dccff4ba5e8b50fc666f84c176ab12a18bb16f8398fe3b71f4afd5f2fc480ffbb607a0a1867a48071660a189b53c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89202c6f353c078410a182f4c01e3452960bc38058c4b943111c615bc8cf972192d0fc7fffc7b32ff738c81271775cf29d3774f4afe7f6bccbf4fda56eeefc6e1bd25bcff13eec9fdb61dc7bd23a5feb65db1ffb7cac4982f9791eb3e76fc1ecf5878f07b9151dfad6160cc97cbc8f5fd17fc8ede5878ba40b3ce08cd1818f3e53272dd2b57eabd9c784f7f5784660c8cf97219f1beea047942cdba4be0e901cdba23346360cc97cbc8755f7216628c85a71734eb89d08c81315f2e23d377db42cd7a4be0c1ef80f54668c6c0982f97d1f2ac61d2acaf049e35a0595f846692189127e9dfc9ee8b88c5f19dc152db4e0cc83825058c5353c088f749708c5fc5ee93e8e3d5275fae3e5ce7abd87d12189be1fb31a116f87d88bfa5c53a5e9ea2f74960ecf54c5ae0f755fe9616eb8187e3fb33598831161e626880d74d4f01e38c1430ce4c0163730a1867a58071760a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a18f1b32ac3b562d1cf2feb2778ecb8cf2a133d76dce792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d73fcca38f11891a725399e1cb61d63f50b687b7f044f86a9ed186ba380b61343da1837a480714d0a1855c7c23d88e5305a9e4d4c3c1b4be0d9043c9b99783695c0b31978b624cf13e6d4e6127888a1015eb726058c1b52c0a83aaa8ed6ec967b729bea2888310d3a2aa3322aa3329e0bc6348ce1ca988a7ccc97cb6879b626cf136ab6a5049eada019bdae8d97315f2ea3e5d9963c4fa8d9d61278b681665b23346360cc97cb6879b627cf136ab6ad049eeda0d9b608cd1818f3e5325a9e1dc9f3849a6d2f81670768b63d423306c67cb98c966767f23ca1663b4ae0d9099aed88d08c81315f2ea3e5d9953c4fa8d9ce12787681663b23346360cc97cb68797627cf136ab6ab049edda0d9ae08cd1818f3e5325a9e3dc9f3849aed2e81670f68b63b423306c67cb98c96676ff23ca1667b4ae0d90b9aed89d04c2ae39a14306e480123b38ef972192dcf3e269ebd25f0ec039e4b9878f695c07309f05c9a3c4f98539794c0430c0df0ba352960dc900246d5517594c4a83a568e8ecaa88cca581a637f0a18f55c2ba3544686cf5745bf4373c9048fdde8c56eac90d871dfa199e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1f7271f3b5fea6fccec071e8edfbc616a67ce1ef73277acbf24a89fd5ea724fab4b3cad1aa0ce65a0dfe50cfa65202e1d9bf6295ea9cc4f11c0cc143b6fc79729d07e8ab1c1d3c3c6bf82a9ed7163fd15133c76dc583fd163c78df5133db6e6b9e67925c4d63cd73caf84d89ae79ae7526263b93618b96ea7df3fb5c778aa2bd7b87d64253fd5b97452e1715aa07d8823b6f6217dafa884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3c6f80e7abc68127f07882223c8b84f1cc11c6335d18cf14613ccb84f1540be3592f8c673ceee72b856797309eedc2787a84f12c16c6b35c18cf5c613c79613c3384f1740ae3992a8c678b309e1a613c1b85f1e484f1ec11c6b34418cf3c613c3385f1ac10c69315c6532b8c6793309ed5c278960ae3d92b8c67b7309e3e613c3b84f1f40ae3e912c6335f184fbb309e66613cadc278ce13c6532f8c67ab309e3a613cab84f1ec13c6b35618cf02613cb384f13408e36914c6334918cf3a613c3b85f16c13c6d32d8c67a1309e0e613cb385f1ac14c6334d184f93309ecdc278260be3c908e0c90667ff2659169edf0fbe2aefb5f67aa0ad79e4f92b9dbf0a5e73952b57471cfb4af0d177c3af8a782dea7425b4a5df95734f6e0b75c258fdb04ff1ea81e32a213c9385f16c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e6dc278760ae359278c6792309e46613c0dc2786609e359208c67ad309e7dc2785609e3a913c6b355184fbd309ef384f1b40ae36916c6d32e8c67be309e2e613cbdc2787608e3e913c6b35b18cf5e613c4b85f1ac16c6b349184fad309eac309e15c278660ae399278c6789309e3dc27872c278360ae3a911c6b34518cf54613c9dc2786608e3c90be3992b8c67b9309ec5c2787a84f16c17c6b34b18cf7e613ceb85f1540be359268c678a309ee9c278e608e359248ca72a8287e1ff5f863c74ff1a1d9bf6f70b89cd701ec2fffb7935539bae71c7aa75c7257e8a570375ae750385bdbf0a5f4b5cfefd86f8de740d68740d535be87c64bcf3c31c3b8ff75506c01078fa04113c1cf7a332b573541e26f8ff677356ab6b3dadfc73d70075ae06fdae65d02f2ab7ffda07dc631a992d0f5d9b116b16eaad17c248be2b7879c27ebb3e18bd15ebb7d7020fc718c6d4ceb07f5de7b5697d84ee540773f53a867646f51ddabf0ece43da982dcf465726d62cd4db2884917cd7f0f284fd6b63307a2bd6bfae031e8ef187a99d61ffbade6bd3c608dda90ee6eaf50ced8cea3bb47f3d9c87b4315b9e4dae4cac59a8b7490823f9aee5e5e9c8429b692bd6bfae071e8ef187a99d61ffbac16bd3a608dda90ee6ea0d0ced8cea3bb47f039c076556e62866cb43dfe122d62cd4db2c84917cd7b1f274e4b2d066da8a8d6337000fc738cfa47b388edde8b5697384ee540773f546867646f51ddabf3122764b90ac16378d418b9b22786e1a672d285ea9cc57a7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5d96eaab3eaac3aabce4930abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac7314bd0d9f2d06f66116b16ea6d11c248beeb7979c2ef056d09466f196fbf1fca3701cf0d0cfa30b533bc87fc80d7a62d11ba531dec5f0718da19d57768ff009c87032530df984266d5b93c66cb43bf4d4fac59a8b7550823f96ee0e509c7b1adc1e8add83876007838c679a67686e3d880d7a6ad11ba531dec5f030ced8cea3bb44ff1945999e3982d0ffd8f2862cd42bd6d4218c977132b4f3efc7ee3b660f4566c1c1b009e0389f314c63106ddc371eca0d7a66d11ba531dccd5830ced8cea3bb47f10ce4329cc37a6905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff0a22d62cd4db2e84917c075879dac37587edc1e82de3edf743f920f00c24ce53587760d03d5c7738e4b5697b84ee5407fbd721867646f51dda3f04e761a233df984266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667872b136b16eaed10c248be015e9ef0770f7604a3b762f7ed1c029e830cfa30b533bc6fe7b0d7a61d11ba531dec5f8719da19d57768ff309c076556e62866cbb3d39589350bf5760a6124df415e9e701cdb198cde8a8d63878187639c676a67388e0d7a6dda19a13bd5c15c1d64686754dfa1fd41380fcaaccc51cc9667972b136b16eaed12c248be43bc3ce138b62b18bd151bc7068187639c676a67388e1df1dab42b4277aa83b97a84a19d517d87f68fc0795066658e62b63cbb5d9958b3506fb71046f21de6e5c967a1cdb4151bc78e000fc738cfd4ce701cbbd96bd3ee08dda90ee6eacd0ced8cea3bb47f339c87b4315b9e3dae4cac59a8b7470823f9067979c2feb52718bd15eb5f37030fc7f8c3d4ceb07f1df5dab4274277aa83b97a94a19d517d87f68fc279481bb3e5d9ebcac49a857a7b853092ef082f4fd8bff606a3b762fdeb28f0708c3f4ced0cfbd731af4d7b2374a73a98abc718da19d57768ff189c87b4315b9e7dae4cac59a8b74f0823f9f0fd621f134fbdc7531fa1c5448cdde8c56eac90d84d5eeca60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc39d43c730e35cfa8e62235ff4b72b13b1b8291ad0a621d656a276efd50c6f939da1609e399238c67ba309e29c2789609e3a916c6d3238c67b1309ee5c278e60ae3c90be399218ca75318cf54613c35c27872c2789608e399278c67a6309e15c278b2c2786a85f1ac16c6b354184f9f309e5e613c5dc278e60be36917c6d32c8ca75518cf79c278ea85f1d409e359258c67ad309e05c2786609e36910c6d3288c67bf309e49c278d609e3e916c6b350184f87309ed9c278560ae399268ca74918cf64613c19013cd9e0ecefa3e0f709aac147f7f7ef03dfd35c793ff8aa2262d0718e818fe673e918f6fd6a6df3d90c55f09a5b22b89e16118fe2dc12f1daf1d01d63f5c33ec5ab078e5b84f04c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e75c2782609e3d92f8ca751184f83309e59c2781608e3592b8c6795309e3a613cf5c278ce13c6d32a8ca759184fbb309ef9c278ba84f1f40ae3e913c6b35418cf6a613cb5c278b2c2785608e399298c679e309e25c27872c2786a84f14c15c6d3298c6786309ebc309eb9c278960be3592c8ca747184fb5309e65c278a608e3992e8c678e309e45c278aa2278f633f1c4fd9ec27e01b1edbc375d0bd29c58169e1f8fef29edf71869ff2830920fefd3cd31f1c4fd06454e406cabc56a28db2d0bcfe3f74cb8722ae731d27e544ee17d96ab9978e27eb763b580d8560b5a1ba07b00b2f03cde57cd9553ab3d46da8fcaa9265e9ef07f4bac0a466fc5ee35c23ec7710e99da99c3fe97e06f6844fe16f52a4fab06a8331ef715c78d07144f9995398ed9f2d0da17b1e2fbd9787c6f692c8c51efaf0c3ce1f8d81a8cde8a8d8f478187e3fd83a99de13876dc6b536b84ee540773f538433ba3fa0eed1f8f88dd1224abc5893168712282e7c4386b41f14a65de9f4266093a5b1eba579358b3506fa51046f2e57879c2f17165307a2b363e9e001e8ef70fa6768663c249af4d2b2374a73ad8bf4e32b433aaefd0fe49380fa5301f4f21b3ea5c1eb3e5a1351a62cd42bdbc1046f21d65e5c9e7b2d066da8a8d63278187639c67d23d1cc786bc36e52374a73ad8bf8618da19d577687f08ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4dd6162cd42bd76218ce43bc1ca535877680f466fc5d61d8680e764e23c85750706ddc37587535e9bda2374a73a98aba718da19d57768ff149c076556666556666556666556666556666556666556666556666556666556666596cd6c79e837e489350bf53a843092ef242f4ff8bdad8e60f4566cdde114f070accb30b5335c77b8d56b534784ee540773f556867646f51ddabf15ce83322b7314b3e5a1df1e24d62cd4eb14c248be21569ec2fa6967307a2b368edd0a3c1ce33c93eee13876da6b536784ee540773f534433ba3fa0eed9f86f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f86c49a857a5d4218c9778a95a73d5c77e80a466fc5d61d4e030fc7ba0c93eee1bac319af4d5d11ba531dec5f6718da19d57768ff0c9c8789ce7c3c85cc9a1be3c3acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc72c21372c4fb72b136b16ea750b6124dfadbc3ce1ef1e7407a3b762f7ed9c019ed30cfa30b533bc6f67d86b537784ee5407fbd730433ba3fa0eed0fc3795066658e62b63c3dae4cac59a8d72384917ca77979f25968336dc5c6b161e0e118e799da198e63b7796dea89d09dea60aedec6d0cea8be43fbb7c179481bb3e5e9756562cd42bd5e218ce4c3f7e55e269e7a8fa73e428b7315db6ad1e7cae7b9c72c3cdf078c5ce361afc748fb98e3e4ab079e3e269e468fa731428b7315db6ab116ca76cbc2f36b81912ba7fa3c46da8fcaa946e059cbc4d3e4f134456871ae625b2dd6b9f234f79885e7d70123574eadf518693f2aa79a80671d134fdc98b46e1c62c7f5aff1881d972be3115b3557cd5573d59c53f3cc39d43c730e35cfa8e6a23467b88e0ae77b2946000cb8f543193f2b705c7b32b53317f5796c9dd726fc3c86730ee7eaf386322b731c33d3bc4547d68b4dfa041e0f6dc3cc5a8ce7bc699fd7a634cc9b16633e9e4266d5b93c661bfbf6e4637764bdd8a44fe0f1d0763bb3164ced0cc7833b82688d295e03d4c13cbd83a19d19884bc7a6fd3be03c94c27c3c85ccaa7379cc36f69d89c72efc9e3cc6267d028f87b63b99b5e06967613cb82b88d698e235401dccd3bb18da9981b8746cdabf0bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9e78ecc2fc3dc6267d028f87b6a7336bc1d3cec2fcfddd41b4c614af01eae039bf9ba19d19884bc7a6fdbbe13c28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c661bfb19c9c70ebf8f83b1499fc0e3a1ed19cc5a30b5339cbfbf2788d698e235401d3ce7f730b4330371e9d8b47f0f9c076556e628661bfb9989c72eace7616cd227f078687b26b3163ced2c8c07f706d11a53bc06a883e7fc5e867666202e1d9bf6ef85f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393adbd8f7251ebb3d9cbfc7d8a44fe0f1d0761fb3163ced2cccdfdf1f446b4cf11aa00ee6e9fd0cedcc405c3a36ed53bc4a603e9e4266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b36f6b3928f1d7e9f1d63933e81c743dbb398b5606a6778ffcb0341b4c614af01ea609e3ec0d0ce0cc4a563d3fe03701e945999a3986dec07938f9dcf7ab1499fc0e3a1ed41662d98da198e070f05d11a53bc06a883e7fc21867666202e1d9bf61f82f39036663c7f93938b1ddeb74931aadca3f53ddb95abc1f71c57ae01df735db9167ccf73e53af03ddf952781ef05d01ef2bdd0955780ef45aebc0e7c2f76e5b5e07b892bf781efa5aedc0bbe97b9f230f85eeecab781ef15ae7c3bf85ee9ca7780ef55ae7c27f85eedca7781ef35aefc74f0bdd695ef06dfeb5cf919e07bbd2bdf03be37b8f233c1f74657be177c6f72e5fbc0f76657be1f7c6f71e525e07b38c2f756577e16f8dee6ca0f80efedaebc1f7cef70e529e07ba72b4f05dfdf41991edfe5cae781ef1157ae07dfbb5db9017cef71e546f0bdd795a781ef7daedc04bef7bbf274f07dc0956780ef83ae3c137c1f72e566f07dd8956781ef23ae3c1b7c1f75e539e0fb982bcf05dfc75d791ef83ee1caf3c1f749575e00be4fb9f242f07dda951781ef33aebc187c9f75653cbf7fefca0f828fc69587c047e3cab3c147e3ca73c047e3ca73c147e3caf3c047e3caf3c147e3ca0bc04779f742f051debd087c94772f061fe5dd4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f730f828efde0a3ecabbb781afc595df0ebef35df91de0bbc095df09be0b5d19c7998b5cf95de0bbd8951f011f8d85ef06df535cf93de05beacaef05df32577e1ff896bbf2fbc1b7c2953f00be95aefc41f0ad72e50f81afd5953f0cbed5aefc11f0e55cf9a3e06b73e58f812fefca1f075fbb2b7f027c1daefc49f075baf2a7c0d7e5ca9f065fb72b7f067c3daefc59f0d1fb388d33b63fdb3e483a9046d6476d6e8d680bf926435bfa8364afe928161d9bf6db8191ce417efc19f363656cf3182d4f2783669857b415fbccd4093c1d0c3c4ced0c3f3375796d6af7dad400759e02edec62686706e2d2b169bf0b62739c73d4a2d61d77a9a7450dd6716f68f6bdb3988e740c9bbff988b6f432b7858e4de352ef38c4eef662e7bcd8381ed356ac7f7503730f03b33d6e5ff2c70dfbd71a772cca298a938336ad050d926a13c6ce38a338e4af81f2bce691ba548ff4a0f72f62b7b94ce712d9fdd7757aaf6b803abd11edef0f926d7f9fc7d3e731db73d2d83cc2c1d01fc21ce8f538683f07daf5c568d70bda511d7cffcb3369d7e3f1f478b12d0f5de374818fae15881fafb35ac781db1ff7ba22b8c9d70d8c51d73a6dc93316bdd6690346f2f5004f379366feb95eeae983efcb755e1d7a6d0dd4590def8dd988bab6df2dc98cb48b3e83ff2548764caf63d00be70702d027f0340c402f6a672d03cfd460648ee0ccf0d0e9819b072f1b1c389c01b41a0f131f3311cda8021f96ab237c41307a2a04a764692a04a764ab3c59700a86eadb8f52b65934dd3078e2d8f0534f0e9e3c74faae53c38387f70cdd8cd4b51e3d92c6b50049d147dbe46064d2a63f487631a6ce8b552c7926c3e3a4e479da98da19bee94df1da54e7b5a901ead4c2735318da9981b8746cda9f12113bc18128d462ea18b4981ac133759cb5c0896ff2614fa5e771f1a4ca6b0bf6686c939fe7893688022e81e3671c9c7dce76f65ad79849c1c8c9a6d1d3cea8daab5a7b22ec0ca97de7b233a07608b2339c7646d3bea9d9194b3b43696724ed0ca49d71b4338c7646d1ce20da19433b43d812146600ed8c9f9de1b3337a1703db1781d77eaab6ef907646cecec0d919377b65653fb1d9ab117bf56daf14edd581bd2ab09f2ced2c837db7b55732f65ddabeb3da2b457b8568afe8ed15ae5da55a6f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31766950985dbfccd8e5c6ae30f65463571abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8016303c60e1a3b64ecb0b14163478cdd6ceca8b163c69e66ec96a07087ce0963278d0d193b65ec5663a78d9d090a2b667685ccae88d91530bbe26557b8ec8a965dc1b22b567685caae48d915a8fb82c20a935d29b22b437655c0ae02d8597f3bcbffdca0308b6f67ed5f101466e5ed2cbc9d75b7b3ec7656ddcea2db59733b4b6e67c5ed2cb89df5b6b3dc7656dbce62db596b3b4b6d67a5ed2cb49d75b6b3cc0f078559643b6b6c6789edacb09d05b6b3be7696f791a0308b6b676ded2cad9d95b5b3b076d6d5ceb2da59553b8b6a674ded2ca99d15b5b3a076d6d3ce72da594d3b8b69672ded2ca59d95fc9cb1478dfd83b17f34f64fc6fed9d8bf18fb57639f37f60563ff66ecdf8dfd4750c8cbff34f625635f36f615635f35f635635f37f60d63df34f62d63df36f698b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1c78d3d61ec77c67e6fec0fc6fe68ec4fc1c8ea060e227f763b34d33e303c3c78e2d470cbf050cb89db8e0f1f3b75fcae963b8e0d1f6d19ba7df0f491e34377e08bdfe5862d5a46d878faf4c05d2dc74e1e1ebcb365e8b6e196a1232d07876e3b79f80cbee8f3ee450bce8e3870f8707cb06f573d09d2ef9519f4d7ee75b440b3b378db1e2f47903f95f3a219d5e535e812f7ae439fde2f2f5cedb69c393e34dc926b3969fe0e1c37af193cdcda82cf9d31229f196e39333c707ab8e5c8e9a1132d6dad78dc6ba694d1889ae6325ed4da3cf69607ff0f1d686fac2d0a0400", + "packedBytecode": "0x000000028df71de500000047641f8b08000000000000ffed9d77781447baee5b20e22001ced9c2f6ae033616424409189c73c6c618631002830d88689c713639384772cec1648c0163eccdd9bbeb0db677d71bce7dee73ef9fe79c7b8fefed9aa9efe8a5a81e3472d7f04a53fd3ca5a9fe54dddfafdefeba3a55771504e9e95f612ad0f9a661ba20387a92ff27f56fe9779b3ac7b8ae52979c050d84b34903e16cda40380b1b0867b306c2d9bc8170b668209c2d1b0867ab18390b80cf156feb06c69b6860bc6d828611b7450d84b3b88170b66d209ced1a0867fb06c2794203e13cb181709ed440384f6e209ca73410ce531b08e7690d84f3f406c2794603e13cb381709ed54038cf6e209ce73410ce731b08674903e1ecd04038cf6b209ce7c7c8d91138e55efef7f4eff7f5ef85faf722fd7bb1febd44ff76d4752cd4f39786e9b230750ad3e5c6ff9430ea867e5998ba18ff2b0f53d730750b5377fdbf12fdbf1e61ea19a65e61aa085365987a87a94f98fa6a3dfa85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bbc2d43f4c7787e91e83654098ee0dd3c030dd17a64161ba3f4c83c3f440988684696898aac2342c4cd5611a1ea611617a304c23c3342a4c0f85e9e1308d0ed398308d0d534d98c685697c98268469629826856972981e09d31443b347c3f458981e0fd31306e793617a2a4c4f87696a989e09d3b3617a2e4ccf87e98530bd18a697c2f47298a685697a9866846966986685697698e684696e98e685697e985e09d3ab617a2d4caf87e98d30bd19a6b7c2f47698de09d3bb9a457684f7c2f47e98168469619816856971989684696998968569799856846965985685697598d684696d98d685697d9836846963983685697398b684696b983e08d3b6306d0fd38e30ed0cd3ae30ed0ed39e30ed0dd38761da17a68fc2b43f4c07c274304c1f87e950983e09d3e1307d1aa6cfc2f48330fd304c3f3234ff71987e12a69f86e967daf673fdfb0b5d56f6f95feadf5fe9df5febdfdfe8dfcf8df2bf35e67f67ccff5eff7ea17fffa07fffa87fffa47fffac7fbfd4bf5fe9dfaff5ef5ff4ef5ff5efdff4ef37faf7effaf71ffaf79ffa573dff7bb5433adf32a89d92414c6d52f9f0a1eafebf886d3e5f54cfae9aeaffc96f89b617ea79f92dd0f6667abe99616faee79b1beb69a9e75b1af6623d5f6cd8dbe9f97686fd043d7f82613f49cf9f64d83be8f90e604fe8ffa52b96fe51b6a6da54003689cf26606ba66d4dc1d65c5607b616dad60c6cb27d9b83ad95b6b5005b6b6d6b09b684b6b5122dc3d446db92415cb1523a54adb728eef5ea6726c5f1f356a9f5b675c4db2e7ede616abded1df0aaf83841afab08e2e6446d2b06db49dad6166c276b5b3bb09da26dedc176aab69d00b6d3b4ed44b09dae6d2781ed0c6d3b196c676adb29603b4bdb4e05dbd9da761ad8ced1b6d3c176aeb69d01b6126d3b136cbac90dce02db79da7636d8ced7b673c07681b69d0b3639c72b019b9cef75009b9cfb9d0736390f3c5fdb54dbd1aa00fc69bbb45b297fd26683edfbd25e83ed4269abc17691b4d360bb187c8bed12686bc4d651dba4dd52ffeba5f3c920aefda42cb59f54c4bdde70cd6abdbde35f6feaf95d9fa056eb24f8a900adfaea7c8c7d5b3aa36f39b7113f622f84fc0d5056ca891e72ec1176752ca8d4f9be1996eb652c570c652a2df54f06f1d6bfb7c1d3db606e06793731dba5d4c76c9da7ac6376009435634fce831a63ccde0c1c0e62b6dcc76c9da7ac6376049435634fce851b63ccde071c0e62b6879b982d2bf5319bbe371604f6d893eba1c618b3a38023fe98edea63b6ee53d631fb1c9435634fae891b63cc4e018ef863b67b0f7f6e50e729eb989d0765cdd893fb338d31665f040e07313bccb7b3759eb28ed90550d68c3db957d81863f655e0883f667b3a8ad92e3e6683f473ce20b0c79edcb76e8c31bb1838e28fd961fefe6cdda7ac6376379435634f9ea134c698dda8f3ea39c3cff57386b3c0f60b6d3b1b78e38fedea3247b1ddd9c776baff4710d863549ee735c6d8fe48e7551cff0afa2388edd7d257016cbfd1b6f3c0f6b9b69d0ff572b00f74f7fb40ddeb94ed3ef047286bc6b23c5b6e8cfbc02f80c341ccf6f0315bf73a651bb3ff0665cdd8937e0e8d3166bf040e0731dbd3c76cddeb946dccfe3b943563ef229d6f8c31fb3f755e9d2f7ca1cf172e01db1fb4ad23d8fea86d9782ed4fda7619d8feac6d9dc0f6a5b65d0eb6afb4ad146c5f6b5b67b0fd45dbcac0f6576deb02b6bf695b39d8bed1b6ae60fbbbb67503db3fb4ad3bd8fea96d3dc0f62f6deba96daa9f9ef4bd3aac6d2d813f19c4bb6da5dfa5ac5be63be7c0775bc377db1cfa6e6ff86e6ff15de6c077027cc85460cc27215fe696a7b41878d05779fcbebaa8ba7709ea5ef772e0e9eaa0ee09f051179eaec0d32d7e9ed4f1b37bfceb4d6de32e86a609f0d505ead5c341bd0ac097ac5be6c55f31d8b06ded6161ec193f635901f89275cb7c4f60141bb6f5f22e95ec3fea787861412daf837d29754e24fee4db55c2510e76297371875ab68e9aad08fe8fc7bd6e86cd515ca6e2427cc9ba655efc15417dbae59eb1acae8c5d0d46576d4401f892757bdfb5db41f2781c7771ad636bd3c477450e7cf7347c971bbeb1ed9429d3b1ad2730c77ecda98f6d95f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfa5a0b6ac94133da41d167615cbb22d91dd5cae87b15c3194a9b0d43f19c45bff4a83a7d26056dbe44a38163ad81f5231506170c87c39685719a15d056827652e02ed5cb567bd0c1e99ef063cd28e75071e57d744513cb9b81e3b966f3c87c5eb67f93f9e07b8da5e9d0d4699b76daf9ec0683b5771703d93f15ca52b308aad17f07471a459d476ed42e2db41aca4da23f121e7e6b2ff7603bb94e9a95fa8536de543d056ba88118c4799ea7acd1bff762a4b5d8377cd8207b79d83ebaace8ee2b114efdf7c1bc41b6b66bbd4d5d02aea1e8fabb6bc8bc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae1b09a3d9ffcdd57dfed4370cf5ba64fdeab9ceff71da1facac14fbc7483f884b8c3a174299a226b565ff1ff407339f53611fc96e6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77fa5b942e9eb7a93ed6ea3b9a66dfcf6e164d5df47f464d0b0c4db13ffea5068f8ad3caa6b56c2e9efd65fb2c12b5927c9ccff68a037bacc7bf5dca8e7866dd2438b2fdc0e38cabfe3bd256cbf3f20ac377219439b349edb691be5532ce6c176339ecf723eb96652e017ba5b1ee767a59e16866acbf3b2c2b65ce8136f540935acd1cb49565d9f65dc7e7e6f11f87d3cff1bb64c1d319785cb4338ece378ef8de6adccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c8431477d1f52cf33e45b65b2fed4f7829bd4fa75fd1c4e9e397534ea8cef8efeef26b565b7ea7c5170747f87a86de9eafb1451db52fce1b767f059908be7ba05e04bd65d66d142f225b1f92e733636843cc7ef62e85a6ed1d4d5fe8acf585153dc5fbb1a3cf86c34eadb3e6586cd65dfa1a8b8107fb82f95814df2f87eb48bed8cc712b35f8ff8c3e7d73fd2dab60b5c6dfbb25297ed067e3725191c1ddff83d959f43dbf74b9dc73e1cd877e46bcbff65caf49c5af4537576f07dcdd20258976c5fdbb73dfb016b4cbe3be3ba0a74ea67685008f9af9ad49695725256b41676b58fc8376090dd5caeabb15c3194e963a97f3288b7fee6b756fb1acc6a9bfc06e2ec6b38febb6a93fa446874096824651c7fb3d1dabfd2ec5788ed6873a38c2c8bdfa2fb17b45151fd476dc700d7c73159b7ed38661e17ead2cf33dffb69fd07b41771f7d3fa0f8821eca71518ebef08eb17aee641f4b145cafc97b17ef39c5c96c17e60ffbd9fc0f75cca743e9b73f2e3757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c6badb56cb3ca08ee9e96658b229615adcc6f85150547ebe7e63b6be97dbeaf5117896bfc06b9943911eae2e6bc257d0ee8ea9b7249a893ca9759ea2a654e837ded0c9d4fc076c2fdf662cbff65ca740e8863b85f117f9d53dbf74ae04c821ff47d15b0c6e4bb33fa967340f123f642c85fd4b4b6ac94133d446b6157fb889c4721bbb95c85b15c3194e967a97f3288b7fe57183c5718cc6a9b9c0d717631f44377d556f78bd0a823682465f09ea2ed3ba0b67b1daededf883a97c2f797ccf32b3c4eba396fb29fc79af7d56ce7081d0d7e3c47e80eed6cc252d6bc5f28c7cb38fb0de3bb12ddc12fbe2be1eadbcdbd40b724cce379c1f1f4ede23bb6ca5fd49809bd72e03b6acc845cf86e6ff86e9f43df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b028c2ec6724804477e7bfc588c38be832cd714185d1c1fb2fdf679776094e50a81d1c5bba538fe465d18f11bc3789c174607df8aed5cdf6fc5e23dbde6c0c8f4ce263e9b6a018c2ece8bebfbae1e9ecfb7845f57e31275c982b10c1865b956c0e8e2de385ecbd48511af8b64b9d6c0e8e21956b6e33be1b7e7f1deb24bc64cc776c77d51cab2bdf752e99627e3b906fa7630ae614a0bbccf782c2d7abbe5c978ee83be1ddcf74b6981e30c1e4b0b7c36e862dcc34470e473b863f1e0f34b59ee04604c3a62ec9b05631218fffb5e3130f673c498cc82b11f308afd24607470ff35c5d82f0b46bc4f29cb9d0c8c573a62bc220bc62b8151963b05185ddc4b4d80dfba305e058cb2dca9c078b523c6abb260bc1a1865b9d380f11a478c5767c1780d30ca72a703e3b58e18afc982f15a6094e5ce00c6eb1c315e9b05e375c028cb9d098cd73b62bc2e0bc6eb8151963b0b186f70c4787d168c3700a32c773630dee888f1862c186f044659ee1c60bcc911e38d5930de048cb2dcb9c078b323c69bb260bc191865b91260bcc511e3cd5930de028cb25c0760bcd511e32d5930de0a8cb2dc79c0789b23c65bb360bc0d1865b9f381f176478cb765c1783b30ca721700e31d8e186fcf82f10e6094e5be078c773a62bc230bc63b815196fb3e30dee588f1ce2c18ef02c63b2d8cfd1d31de9505637f6094e52e05c6bbe3674c5d4bf7cf82f16ee0b9277e9e94667767c1738f5b9ed477f5eeb6f8ba377e5fa96d3120a87bddef059e81f1f3a4b6c5bd59f00843312c879add173f634ab3815930de073c83e2e74969765f163c8340b3fb2c9add1f3f634ab3415930de0f3c83e3e74969767f163c8341b3fb2d9a3d103f634ab3c159303e003c43e2e74969f640163c43825acd1eb06836347ec6946643b2601c0a3c55f1f3a4341b9a054f156836d4a2d9b0f819539a5565c1380c78aae3e74969362c0b9e6ad06c9845b3e1f133a634abce827138f08c889f27a5d9f02c78468066c32d9a3d183f634ab31159303e083c23e3e74969f660163c2341b3072d9a8d8a9f31a5d9c82c184701cf43f1f3a4341b9505cf43a0d9288b660f3b627c280bc6872d3c717f27fb218baf318eea3e3aa87bdd85a11896c37e12631d318ec982712c30ca72d84fa2c611e3d82c186b8051964b3866ccd44fa2067c8f8bdf77aa5daa09eaaecf38b73c19fb49a0eff18eb41817d45d8bf16e7932f69340df131c69313ea8bb16138067a2032d12e0a32e3cc2500ccb613f89498e182766c13809186539ec2731d911e3a42c182703a32c87fd241e71c438390bc647805196c37e12531c313e9205e3146094e5b09fc4a38e18a764c1f82830ca72d84fe231478c8f66c1f81830ca72d84fe271478c8f65c1f83830ca72d84fe209478c8f67c1f80430ca72d84fe249478c4f64c1f82430ca72d84fe229478c4f66c1f81430ca72d84fe269478c4f65c1f83430ca72d84f62aa23c6a7b3609c0a8cb21cf69378c611e3d42c189f0146590efb493ceb88f1992c189f054659ee61c78c99ae5f9e6de4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3fe7c077027cc85460cc27212f0cc5b0dcc39eb15133224f497c3ca55877f4f53c41dd9fb7f01438aa3bfa7a81a0eec2d0d0189f6b008c0f370046af63ba0f627d1815cf8bf0ff648c3c2f64c1f322f0bce488e7c52c785e029e97e3e749c5d44b59f00843312cf77003607cae01307a1dbd8e4c8c5ec7fcd1d1337a46cfe8198f07634368c33d638388c7b2fa322a9e69f1f3a4347b390b9e69a0992c778f5bc6b2fa322a9ee9f1f3a4349b9605cf74d06c9a4533078c65f565543c33e2e74969363d0b9e19a0d9748b660e18cbeacba87866c6cf93d26c46163c3341b31916cd1c3096d59751f1cc8a9f27a5d9cc2c78668166332d9a39602cab2fa3e2991d3f4f4ab35959f0cc06cd66593473c058565f46c533277e9e9466b3b3e099039acdb668e680b1acbe8c8a676efc3c29cde664c13317349b63d1cc0163597d1915cfbcf879529acdcd82671e6836d7a2192be3c30d80f1b906c0e858c7b2fa322a9ef98e78e665c1331f785e71c4333f0b9e5780e7d5f8795231f54a163cc2500ccb3ddc00189f6b008c5e47af2313a3d7317f74f48c9ed13366c7f87c0360f4dbda33b2323ab8becaf80ecd2b8ddc77d43b348ddd77d43b348dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97e2d7edf65d97e63e635e071f1cd1b47f52c55eb7d5dafebdb18f5535abd6168f58aa1553194791df47bc3817e05e057d62df3e22f5be60b09981df92e53ed4b2ba8bff878ced043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7316df986f16d49eb7cbf74fd53aded2f9423d2fe59f07bb9499d822fddb2ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff57e680273078820c3cf3c8782693f1cc24e31949c633888ce756329e2bc9789e24e32927e31947c6338c8ce76e329e1bc8782e27e3e943c633858ca72719cf2c329e87c8785e22e3194cc6733b19cfd5643c4f93f19491f14c20e3194ec6732f19cf4d643c49329ec7c878ba93f15c4cc633868c673619cf45643c43c8785e26e3b9938ca7988ca72d19cfb5643c2f90f15c46c65341c6f30c19cf5c329e49643c0f92f1dc47c6534ac6730b194f27329e2bc8789e20e3e94ac633878ca7868c671a194f15194f7f329e4bc878ae27e3694ac6d39b8c673e19cf23643cbdc8784691f17424e3b99f8ce736329eabc8789e22e3e942c6339e8c673a194f3519cf00329e1bc978fa92f13c4ac6d3838c673419cf85643c0f90f1dc41c6938bef9966c3d3868ca7888ce71a329e67c978a692f17426e39948c633838c670419cf40329e9bc978fa91f13c4ec6d38d8c672c19cf50329ebbc8785e24e36947c6d39e8ce73a329e02029e4470f4182609f8ff6b606b622cab3efb3aba43edffdfd6f626b0cc3b3adfd4b2eeb7c126df927dc7b22ceaf436d425a9f3a5df6d4ae984be92302ffe8a80e31d129eebc878da93f1b423e379918ce72e329ea1643c63c978ba91f13c4ec6d38f8ce766329e81643c23c8786690f14c24e3e94cc633958ce759329e6bc8788ac878da90f1bc46c6730719cf03643c1792f18c26e3e941c6f328194f5f329e1bc9780690f15493f14c27e3194fc6d3858ce729329eabc8786e23e3b99f8ca72319cf28329e5e643c8f90f1cc27e3e94dc6d3948ce77a329e4bc878fa93f15491f14c23e3a921e39943c6d3958ce709329e2bc8783a91f1dc42c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643c1791f1cc26e31943c67331194f77329ec7c87892643c3791f1dc4bc6339c8c6702194f1919cfd3643c5793f1dc4ec633988ce725329e87c8786691f1f424e39942c6d3878ce772329e1bc878ee26e31946c6338e8ca79c8ce749329e2bc9786e25e31944c633928c672619cf64329e79643c95169ed71cf1c8fbeeb26e997f8dc4b783ed50aad6fbaea33abda7d7d54caf57f8c55f219499da3afdabde0fc76585cbfc3e01be9bf31e68f49ea3bac8f62830b60ffa7ecb916f79474bd62df36f3572df6d0ddf6df3c4777bc377fb3cf1ede3dcc7793ef8f671eee33c1f7cfb38f771cee4dbc1b541197e274da602633e0979bc5e70f17d3947f53ce23af1db18f5535abd6f68655e5b1543997741bff71de867bbf69479f1972df38504cc18172541bc71b120fe3a95a976ab15e8bac0d017ebb5d091a651c790858ddc77d431a4b1fb8e3a863476df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe17e97c8cd78da5e8433d5f94eb8145e07789ce17c4e857ad6bb15e57a15eb7702c01bb94f94f78aee9f779bfcfc7e5db1fdb7c9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8668e73332ffdc52f023657fdf9a3623117ef121c4fdf51b1d8d87d47c56263f7ede3dcc73993efa50e7c27c0874c99faf82d059ec50e781cd533f56c639951a7d78c3a1543193cc62f7350cf02f02beb96f965c0235325f0b88883ba6c73e49947c633998c672619cf48329e41643cb792f15c49c6f324194f3919cf38329e61643c7793f1dc40c67339194f1f329e29643c3dc9786691f13c44c6f31219cf60329edbc978ae26e3799a8ca78c8c670219cf70329e7bc9786e22e34992f13c46c6d39d8ce762329e31643cb3c9788690f1bc4cc67327194f31194f5b329e6bc9785e20e3b98c8ca7828ce719329eb9643c93c8781e24e3b98f8ca7948c672119cf2d643c9dc878ae20e379828ca72b19cf1c329e1a329e69643c55643cfdc9782e21e3b99e8ca729194f6f329ef9643c8f90f1f422e31945c6d3918ce77e329edbc878ae22e3798a8ca70b19cf78329ee9643cd5643c03c878de27e3b9918ca72f19cfa3643c3dc8784693f15c48c6f30019cf1d643c6dc8788ac878ae21e379968c672a194f67329e89643c33c8784690f10c24e3b9998ca71f19cfe3643cddc878c692f10c25e3b98b8ce745329e76643cedc978ae23e32920e0490447bffb9f80ffbf0f367947fd35b02dd7f9c5606b62f1d154e79781ad50e7651d2dc234a5c3d1eb469d5cbd978fbe92302ffe8a80633909cf75643cedc978da91f1bc48c6731719cf50329eb1643cddc8781e27e3e947c6733319cf40329e11643c33c8782692f17426e3994ac6f32c19cf35643c45643c6dc878ee20e379808ce742329ed1643c3dc8781e25e3e94bc6732319cffb643c03c878aac978a693f18c27e3e942c6f31419cf55643cb791f1dc4fc6d3918c6714194f2f329e47c878e693f1f426e3694ac6733d19cf25643cfdc978aac878a691f1d490f1cc21e3e94ac6f30419cf15643c9dc8786e21e35948c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643cb3c978c690f15c4cc6d39d8ce731329e2419cf4d643cf792f10c27e39940c65346c6f33419cfd5643cb793f10c26e379898ce721329e59643c3dc978a690f1f421e3b99c8ce706329ebbc9788691f18c23e32927e379928ce74a329e5bc9780691f18c24e39949c633998c671e194f658e78d4bbedd2d73a002e9c92905f063c0b1df038aa67297ed7e0db18d7abb45a6168f5bea1553194590afaad70a05f01f89575cbfc0ae07956e76ddf54789684516c0b1df324a0ce3265da0756008f8b7dd2513d53b1bad2a8d3b316dda50cc6ea4a07f5b4ed3b32bf12785ed079614d40b9174818c5b6cc314f02ea2c53a6585d093c2ef61d47f54cc5ea2aa34e2f5874973218abab1cd4d3b6efc8fc2ae07951e7853501e55e246114db0ab73ce509a8b34c99627515f0b8d8771cd53315abab8d3abd68d15dca60acae76504fdbbe23f3ab613b7866cf6c63563c72ff5e581350ee251246b1ad74ca535e9a803acb94a91d5b0d3c2eda7947baa7dab135469d5eb2e82e653056d738a8a76ddf91f93516df2541bc5aacad83166b2d3c6b73ac85f8cb9679690364f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e6266d059f1c8f709853501e55e266114db2ab73ca9f7825e0e8e9c0a8cf924e4d702cf6a07fa38aa67aa0ff93aa34e2f5b749732b87fad73504fdbbe23f3eb603b64c3bca601327b9debc7ac78a6e9bcb026a0dc341246b1ad76cb936ac7a605474e99dab175c0e3a29d7754cf543bb6dea8d3348bee5206f7aff50eea69db77647e3d6c07cfec996dcc8a67bace0b6b02ca4d276114db5aa73c65a9f71ba707474e99dab1f5c0e3a29d77a47baa1ddb60d469ba45772983b1bac1413d6dfb8ecc6f80ed900df39a06c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9df34767c53343e7853501e56690308a6d9d539e2ea9e70e338223a74ccf1d36008f8be7328e744f3d77d868d4698645772983fbd74607f5b4ed3b32bf11b64363675ed300997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd479614d40b999248c625bef9627f5dd8399c19153a67e3b1b816783037d1cd533d56f679351a79916dda50cee5f9b1cd4d3b6efc8fc26d80e9ed933db9815cf2c9d17d604949b45c228b60d6e7952edd8ace0c829533bb609785cb4f38eea996ac7361b759a65d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3755e5813506e3609a3d836bae549b563b38323a74cedd866e071d1ce3baa67aa1ddb62d469b645772983b1bac5413d6dfb8ecc6f81ede0993db38d59f1ccd179614d40b939248c62dbe4982701759629533bb605785cb4f38eea996ac7b61a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd256114db66c73c09a8b34c9962752bf0b8d8771cd53315ab1f18759a6bd15dca60ac7ee0a09eb67d47e63f009e793a2fac0928378f84516c5b1cf324a0ce32658ad50f80c7c5bee3a89ea958dd66d4699e45772983b1bacd413d6dfb8ecc6f039ef93a2fac0928379f84516cd88ecd77c45364f01459b4385ebe9516153adf46ff26e0ff15c0e8aa6d996f30ca3cc6b8d88a72a0595b83a7ada1d9f1f4adb4a884bc9a707b550223c3f66a9b03cdda1b3ced0dcd8ea76fa5456f9d6fa77f717bf5064686edd51e781cb4cfe50983474d998edddb1cebe3a89ea963f7f6c0ae3b1e87a40c1ebbb73ba8a7ed5c42e6b7c376f0cc9ed9c6ac78faebbcb026a05c7f1246b1e139ff8ef879ca13068f9a32b5633b1cebe3a89ea9766c6760d77d07e82e653056773aa86701f89575cbfc4ed80ed930af6980cc5ee7fa312b9e013a2fac0928378084516cdb816757fc3ce50983474d99dab15d8ef57154cf543bb63bb0ebbe0b749732b87fed7650cf02f02beb96f9ddb01db2615ed30099bdcef563563c03755e5813506e2009a3d87602cf9ed879d263be208f9a32b5637b1cebe3a69ee9766c6f60d77d0fe82e6570ffdaeba09e05e057d62df37b613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c83745e5813506e1009a3d87603cf87b1f3a49f3b208f9a323d77f8d0b13e6eea997eeeb02fb0ebfe21e82e653056f739a86701f89575cbfc3ed80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf609d17d604941b4cc228b6bdc0f351fc3ce50983474d999e3b7ce4581f47f54c3d77d81fd875ff0874973218abfb1dd4b300fccaba657e3f6c87fd9ed9335b9815cf109d17d604941b42c228b67dc07320769ef4f353e45153a676ec80637ddcd433dd8e1d0cecba1f00dda50cc6ea4107f52c00bfb26e993f08db211be6350d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63ae78fce8aa74ae7853501e5aa4818c5b61f783e8e9da74b69c2e0515381319f84fcc78ef57153cff4738743815df78f41772983fbd72107f52c00bfb26e993f04dba1b133af6980cc3e3672c3ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc0cb1a178aa755e581350ae9a84516c0781e793f879ca13068f9a0a8cf924e43f71ac8fa37aa6faed1c0eecba7f02ba4b19dcbf0e3ba86701f89575cbfc61d80e9ed933db9815cf089d17d604941b41c228b643c0f3a9039e84c1a3a64cedd8a78ef57154cf543bf65960d7fd53d05dca60ac7ee6a09e05e057d62df39f01cf489d17d604941b49c228b6c3c0e32256154f91c123f39f12f8565ad4e87c1bfd8bdbab061819b657510e346b6bf0b435343b9ebe9516e320af26dc5ee38091617bb5cd8166ed0d9ef68666c7d3b7d262bcceb7d3bfb8bdc60323c3f66a9f03cd8e677b783cf7ede319a75ef3e3a779c171d4bce0386a5ee035a7d2dcc1f1a50c8f650130e09484fc67c0f3c3f87952f7b83ecb82e787c0f383f8793a3baa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308aed07c0e3a2dd5075bf4caf4bd6df2c4cfb4eaaf5ebe2d903de776da6d72b1ce2af10cadc5e525bf6a0662b82ffcb7653f53964d81cbd0fdcd9f60c4ce6c55f5190bbfba099eecba2162e9edd647bdc3f64e1f9363e9e52dccfd1d7414775cfe639da410b4f8c75ef1cf50cf140fc754fb51f9df4ba64fd6a1ffdfc24a79a97e3be27ed4727a3ce8550e6b292dab25f40fb616b2b5cef9b724e6eee9b4d82daf64cb84ab4dd7cbef2adb64bb94fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3199fe9bb1874f9845433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb4f2c3af6b670f726e066dcaf7b1b3ab26976acfdbabf85bb3f0137e37edddfd0914db363edd7032cdc0308b819f7eb01868e6c9a1d6bbf1e68e11e48c0cdb85f0f347464d3ec58fbf5200bf720026ec6fd7a90a1239b66c7daaf075bb807137033eed7830d1dd9343bd67e3dc4c23d84809b71bf1e121ca9239b66c7daafab2cdc5504dc8cfb7595a1239b66c7daafab2ddcd504dc8cfb75b5a1239b66c7daaf4758b847107033eed7230c1dd9343bd67e3dd2c23d92809b71bfae6bbf7dd6fdbac6c25d43c0cdb85fd7183ab26976acfd7a9c857b1c0137e37e3dced0914db363edd7e32ddce309b819f7ebf1868e6c9ad9f66b47efe59565fb9ee061a7faa4c76b3e9c05cfc7c0e322a61cc541a9a37e2ea9bea9070cad0e1b5ae1381807413f077d6132bedf2ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e3370ef1f98a94fb8484516cf84ccac57d7e55f7cbf5ba64fdcdc2d4f9945abf0763f75b565a60f84b0287f82b8432ff794e6dd9ae9aad28387abbe1b8d6b82df7c75e87f4b634e35fe6c55f11d4e700f038783f3fc573d0e03968d102df3b8dc777d930371a9795aaefefb40a6ab7f37ea33ea8e947b1fb3f52d30243d38f1cfb4e04476e4f61c0290979e471f16cd8513d536dc13ea34ea6c6c550e642a8e73e07f52c00bfb26e99df073c3235011e573118183c81451f992ac9782693f18c24e3b9808c671019cf69643cb792f1b422e3b9928ce749329e72329e71643cc3c878ce25e3b99b8ce744329e1bc8782e27e32924e3e943c633858ca72719cf43643cdf27e3194cc6732919cf19643cb793f124c878ae26e3799a8ca78c8c670219cf70329e0e643cf792f19c4cc67313194f73329e2419cf63643cddc9782e26e31943c6731119cf10329eb3c878ee24e32926e3694bc6732d19cf33643c15643c9791f14c22e379908ce77c329efbc8784ac9784e25e3b9858ca71319cf15643c2dc9789e20e3e94ac65343c65345c6730e194f7f329e4bc8784e20e3b99e8ca729194f6f329e47c8787a91f18c22e3e948c6f33d329efbc9784e27e3b98d8ca73519cf55643c07c8789e22e3e942c6339e8ca79a8ce710194f0919cf00329e93c8786e24e36946c6d3978ce751329e1e643ca3c9782e24e379808ce74c329e3bc878da90f11491f15c43c633958ca73319cf44329e11643ce791f10c24e339858ce766329e16643cfdc8781e27e3e946c633968c672819cfd9643c7791f1b423e3694fc6731d194f01014f2238fa5b4c09f8ff41b0c937833e065b13cbfae439b59457c7c5673b1cbdee2696757f6461409d3e84ba2475bef4bb4d299dd05712e6c55f11707c44c2731d194f7b329e76643c7791f19c4dc633948c672c194f37329ec7c978fa91f1b420e3b9998ce714329e81643ce791f18c20e39948c6d3998c672a19cf35643c45643c6dc878ee20e339938ce701329e0bc9784693f1f420e379948ca72f194f33329e1bc9784e22e31940c65342c673888ca79a8c673c194f17329ea7c8780e90f15c45c6d39a8ce736329ed3c978ee27e3f91e194f47329e51643cbdc8781e21e3e94dc6d3948ce77a329e13c8782e21e3e94fc6730e194f15194f0d194f57329e27c8785a92f15c41c6d3898ce716329e53c9784ac978ee23e3399f8ce741329e49643c9791f15490f13c43c6732d194f5b329e62329e3bc978ce22e31942c6731119cf18329e8bc978ba93f13c46c69324e3694ec6731319cfc9643cf792f17420e3194ec633818ca78c8ce769329eabc97812643cb793f19c41c6732919cf60329eef93f13c44c6d3938c670a194f1f329e42329ecbc9786e20e339918ce76e329e73c9788691f18c23e32927e379928ce74a329e56643cb792f19c46c633888ce702329e91643c93c9782ac9789a183cf87ff56ed8019d976f0715c2ffefd69dcbdbe97549197946acee55ec356caabe7b1cd5776f503b25617e0fd457d8f702cf5e473c1f1a3ca6ef22c8578266bb0d9b62dce58871b7c128f3bb8051f4db0d3cbb1df1ec31784cdf4590ef0d9aed346c8a718723c69d06a3ccef0046d16f27f0ec74c4b3cbe0317d1741be3f68b6ddb029c66d8e18b71b8c32bf0d1845bfedc0b3dd11cf0e83c7f45d04f901a0d907864d316e75c4f881c128f35b8151f4fb00783e70c4b3cde0317d17417e2068b6c5b029c6cd8e18b7188c32bf191845bf2dc0b3c511cf5683c7f45d04f941a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37711e40783661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf45901f029aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d1741be0a345b63d814e36a478c6b0c46995f0d8ca2df1ae059e38867adc163fa2e827c3568b6cab029c6958e1857198c32bf121845bf55c0b3ca11cf6a83c7f45d04f911a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37711e4478266cb0c9b625cea887199c128f34b8151f45b063ccb1cf12c37784cdf4590af01cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be8b203f0e345b64d814e342478c8b0c46995f088ca2df22e059e48867b1c163fa2e82fc78d06c8161538cef3b625c6030cafcfbc028fa2d009e058e78161a3ca6ef22c8df0936e1ed05b6f774be27d8ded5f91e607b47e7bb83ed6d9def06b6b774be2bd8ded4f972b0bda1f35dc0f6bace9781ed359def0cb65775be0fd85ed1f9be609baff349b0cdd3f97e609babf357806d8ece5f09b6d93a7f15d866e9fcd5609ba9f3d7806d86ce5f0bb6e93a7f1dd8a6e9fcf5607b59e76f00db4b3a7f23d85ed4f99bc0f682cedf0cb6e775fe16b03da7f3b782ed599dbf0d6c0febfced60bb47e7ef00db619dbf0b6c9feafcdd60fb4ce7ef05db0f74fe3eb0fd50e7ef07db8f74fe01b0fd58e78782ed273a3f0c6c3fd5f9e160fb99ce3f08b69febfc28b0fd42e71f02db2f757e34d87ea5f363c0f66b9d1f0bb6dfe8fc04b07daef313c1f65b9d9f04b6dfe9fc64b0fd5ee71f01db173a3f056c7fd0f947c1f6479d7f0c6c7fd2f9c7c1f6679d7f026c5feafc9360fb4ae79f02dbd73aff34d8fea2f353c1f6579d7f066c7fd37969d7543bfb779d2f09e26d67bf096aa712f02dfe54997fe87c73a38c2c5b08655aeb0e85ea19877a7749da616997954ddae1f7c026edf0bb609376f81db0493bfc36d8a41d7e0b6cd20ebf09366987df009bb4c3af834ddae1d7c026edf0ab609376f815b025757e3ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae119609376783ad8a41d9e063669875f069bb4c32f814ddae117c126edf00b609376f879b0493bfc1cd8a41d7e166cd20e3f0c366987ef019bec2fdf804ddae6c36093b6f953b049dbfc19d8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe15d8c6eafcafc1266df36fc0266df3e76093b6f9b76093b6f9776093b6f9f76093b6f90bb049dbfc07b049dbfc47b049dbfc27b049dbfc67b049dbfc25d8a46dfe0a6cd2367f0d36699bff02b667745edaea96609367c56a2afd8e138ec3d3047c094b3288b7edc7290979acbb4c95643cb3c8784692f1bc45c6730119cf20329ed3c8785a91f12c20e31947c6339f8c671919cf52329ef7c978ce25e3d944c6b3918ce744329ebd643c7bc8782e27e32924e39941c6f306198fbcf7c9c233988ce752329e33c87812643c73c9789690f12c26e379978ca70319cf06329ef5643c2793f1ec26e3d945c6d39c8ce71b329e69643c1793f1bc46c6731119cf10329eb3c8788ac978da92f15490f15c46c6339b8c671119cf42329eb7c978ce27e35947c6b3968ca7948ce754329e9d643c3bc8783a91f1b424e379898ca7868ce715329e2a329e73c878fa93f15c42c67302194f53329ede643cf790f1cc24e379938ca72319cff7c878d690f1ac26e3f92b19cfe9643cdbc978b691f1b426e33940c6339e8c671e194f3519cf7b643c87c8784ac8780690f19c44c6d38c8ce73019cf74329ed7c9785691f1ac24e339938ce703329ead643c6dc8788ac878e690f18c20e379878ce73c329e81643ca790f1b420e379998ce755329e15643ccbc978ce26e3d942c6b3998ca71d194f7b329e7d643c1f92f11410f0248023009bfcbf29d8e43b3c87c0f6b5ce1f009b7cc36701d8bed2f967c0f694c5d6c4c2270c53c126efca7e0d36b93ff334d8e49d89afc026e70de25fcd4fef70347f135846fc34b5f0a3bfaf2c5c92c7ed2dcb248378b737fa4a06f66fde15188cc79be743329e7d643cedc978da91f16c26e3d942c6733619cf72329e15643caf92f1bc4cc6d3828ce714329e81643ce791f1bc43c633828c670e194f11194f1b329ead643c1f90f19c49c6b3928c671519cfeb643cd3c9780e93f13423e339898c6700194f0919cf21329ef7c878aac978e691f18c27e33940c6d39a8c671b19cf76329ed3c978fe4ac6b39a8c670d19cff7c8783a92f1bc49c633938ce71e329ede643c4dc9784e20e3b9848ca73f19cf39643c55643caf90f1d490f1bc44c6d3928ca71319cf0e329e9d643ca792f19492f1ac25e35947c6733e19cfdb643c0bc9781691f1cc26e3b98c8ca7828ca72d194f3119cf59643c43c8782e22e3798d8ce762329e69643cdf90f13427e3d945c6b39b8ce764329ef5643c1bc8783a90f1bc4bc6b3988c670919cf5c329e0419cf19643c9792f10c26e3f93e19cf1b643c33c8780ac9782e27e3d943c6b3978ce744329e8d643c9bc878ce25e3799f8c672919cf32329ef9643ce3c8781690f1b422e3398d8c671019cf05643c6f91f18c24e39945c65349c6d3c4c273c8118f7c2b46d62df3871ab9ef3d86ef3d79e27b97e17b579ef8de61f8de9127beb719beb7e589efad86efad79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efa586efa579e27bb1e17b719ef85e68f85e9827be99afbf553f5ce9abbc4fff26e0ff15c0b8c011e3218351e61700a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba93dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba95dc0d3db114fd4bd92de04be9516f2eeb3bcf39780ffe378ebae62aab7c128f3b698da013cfd1df144dde3e94fe05b6921df0a936fd224e0ff383ea3ab98ea6f30cabc2da670fcdc018e78a2ee4d0d20f0adb4906fedca372f13f07f1cbfc9554c0d301865de1653387edc40473c51f7d40612f8565ac8b360f9467b02fe3f08185dc5d4408351e66d3185e3dd0c72c413752f7010816fa5c5609d973e5609f8ff6060741553830c4699b7c5d446e019ec8827ea1ee66002df4a8b213a2fef7024e0ff4380d1554c0d361865de1653eb816788239ea87baf43087c2b2daa745edee94fc0ffab80d1554c0d311865de16536b81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb10478c5506a3cc0f0146b1ad069e6a473c51f7baab097c2b2de4dbfeabf46f02fe8fe3b1ba8aa96a8351e66d3185e3418f70c413758f7e04816fa5c5489d97316112f0ff91c0e82aa646188c326f8b291cbf72a4239ea8670b23097c2b2de4db5ccbf46f02fe5f038cae626aa4c128f3b6985a0a3c358e78161b3c8b2d5a1c2fdf4a0be9cbbd44ff26e0ffe380d1554cd5188c326f8ba9c5c033ce114fd4b39c7104be9516f26ded45fa3701ff1f0f8cae626a9cc128f3b6985a083ce31df1443d831a9f03df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe8fe7b943beb6e7c7f3187a3c8f25fedac05f1be4cab73f96f86b835cf9ced76b03df9ee7be3d97ebaf8220fa7a6cb923df4b0ddf328fcf59963af2bdd8f02df3f8cc60b123df0b0ddf328ff7bf173af25d64f896f98539f0ddd6f0dd3687bedb1bbedb5b7cbbd8de89e0c8eb6f61c02909798c81450e781cd5b354ad77895ed7b731aed776dfc6dc5f8aa1cc12d0cf75db21ebced476b48ccf7769027cc837be944d9ec5be07366943df059b3c637f076cd2cebf0d3679bef316d8e4f9cf9b601ba9f387c126cf61b1ffbb3c4bdf01b62a9dc77ed743747e1bd8a45f12f6f795be655bc126fd03b19fa9f4f1dc0c36e9a78bfd1ba5aff546b0497f79ec5727ef3cac079bbcb782fdb9e4dda3b5603ba0f3d88f48bee9b21a6c53757e15d8fea2f32bc1f6a4cedf03b62f75fe1bb0fd59e71782ed099d5f04b63fe9fc12b03daef36f80ed8f3aff3ad81ed3f9d7c0f6a8cee37b617fd0f90fc1f685cee3fb4853747e0fd87eaff3f81ecc233abf0b6cbfd3f957c13659e75f01db249d9f0fb6dfeafc3cb07daef373c13651e7e780ed373a3f1b6c13747e16d87eadf333c13656e76780ed573a3f1d6c63747e1ad846ebfccb60fba5cebf04b65fe8fc5fc1f690ce2f065b139d5f0a36197f11fb7c14eafc72b0c9b8f4d89747be953f1e6c2d747e1cd85aea7c0dd8e43b6b23c126632b8f005b42e7abc1d646e7abc026e73a43c02663890c069b9c970c025b3b9d1f08363987180036191bb23fd8e47b9ebdc17692ce57824dbe535f01b65374fe10d864fcae0560936fc01d009b8c6bfc34d8e4dbcf53c176a6ceff056c32a6c993603b5be7bf04db393aff67b0c9f7309f005b89ceff096c1d74fe71b09da7f37f049b8c37f518d82ed0f947c126e3f0fe016cf2ede42fc076a1ce4f01db453aff7bb0c9b81c8f804dc6dafc1dd83aeafc64b0c937ad2781ed329dff2dd864ecbccfc126dfeb9d08361923ed3760ebacf313c056a6f3bf065b179d1f0bb6729dff15d8baeafc18b075d3f9d160ebaef3bf045b0f9dff05d87aeabcb4336a7f56fbf9413d9f0ce23dcffe383872ca749e2d0cc813e7796b31f0a0affdb1d7bd2c758e2cfb7d13bd5e89a1fde07b5fecbed3e7e71fe97515eaf5ee337c17429996ba7150cbc931bfa95eee80b11cde139275cb329783fd4363dded747d3f7254df7d069370a30e52a68d6652c7c68d3adf12968991ad4ced03126b0168885312f2c2e046abb2523cefad0bcf47c0b33f769ef4b5af8b98c07d2bee6b5ff39ea8196bc550661fe8f7a103fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac780eea3c3e579672074918c5b61f785cdce7c7e7b0b27ef55ce7fd736bfdee8fddef91cff79ae9f5961a752e84327f86674e8b75be08fe2fdb2d6a5b3a784e98715b8abf22a80f3e0b3ae88867bfc1b3dfa285e44b62f35d36cc8dc665a5aadf8a7ac67ec0d0f5a0455357fbeb7ebdae024353dc5f3f3678f0d96811f07ea27f13b09e4fa00e0ef6f18c7121fe705fda0f36c97f0c8c2eb6331e4ba43d90e7e1f86c5acaec329e8bc7bfedcb4a5db61b7ba14ec9e0e8f82e8432fba0eddbaff3d837e420e8f633cbff65caf49c5af45375de1d7f9d53db77177026c10ffade09ac31f93ee27d94029dc48fd80b21ff53e8cf21e5440fd15ad871ec6f643797fbd858ae18caecb1d43f19c45bffdd06cf6e83596d938f21ce7e06c77f576dd29e088d2e078da4cc7ed0e880239efd068f70883f5546b67f73a38c2c5b08657e0b6d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f147c068d651c547e7536a79f7c7cedbb0fa7ffd03da8bb8fb7ffd0362a800380263fda5b07ee16a1e441f5ba4ccff308ea32eae31705b9a7aa2ce52e67f413bf4fd92743e9b73fde375dd1675aebfc7014f2238f2da5b4d998eef788cd9eb80c7513d4b6dc7ae0f8d3a1543990ba19e0ece6332be57bb1b7cbbd8e6a8859c43ed33b42884320525e95f693ba274c46bd58f72529732ebf960a9a52e52a645496d5d5a823d4e2697db6d27d449ad77bfa5ae52a64d49ad2ec53a9f80ed84f74dceb6fc5fa64ced018e6bb33dfe3aa7b6ef36e04c821ff4fd01b0c6e4fb88ef6ac8f9bef8117b21e4cf2aa92d2be5440fd15ad8d53e22effc21bbb9dc3e63b96228b3c352ff64106ffdb71b3cdb0d66b54dda97d4e6258e5cb69b3b22342a058da40cde3f96633bbe77673beeef77c41d75dcdf0f8c66bb89e72e2ed90e186ce63d54dbf9a094c1733229d3b124fdabdad984a56cb3e0c87bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7402fb7e9d179d3b19da154299ae25e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1fbd4a6ab9711cc2fdfab7086c9fea5f47d769e5b67b86c261bb67982ca965c76585ebb0a52ee6357293e0e87beadf1a65f1be5ba6e5ccbc39a6a3d2f753a39ccd0f5ef3c4f6ae46e7d252646a12d8ef177c6cb01704478f5f29fb01c69c791fa593b11ebc8f726b49fa57da24b3acdaf69f9f54ab8f6c47d10edb138cc98f8131a9f3a5df6dea6cabbfcc8b3fc5f8895107376d57fa7da56cee031f001e176dbba336ba148fb1f17d9fa26795edf8ffb1a1550e9fd75a8ff9e633f796463e1edf65d5b6fb4f362df659785c3d4789d2629fc5777c5a741b663b7ed8b4c865df87282d3eb4f88e518b1178df3393167b2d3c2eee4565d262afc5777c5a742fcdf45c03b5d863e17175ef214a0bf1972df38704cc2d8d7c3cbecbab6cf7c96c5aecb6f0b8ba6e8ed262b7c5777c5a74ee86f7e83269b1cbc213fffdb9cc5aecb2f88e4f8b1e3df11e5e262d765a785c3dd38dd262a7c5778c7131dc762fc7a6c50e0bcf8e1c6bb1c3e23bc6f3c36eb67b6d362db65b781cdc77cda8c5768bef18b5188af75d3369b1cdc2b32dc75a6cb3f88e4f8baaaeb67bc2362d3eb0f0b8ba271ca5c50716dff16931b487f2bdb50e5a6cb5f06ccdb1165b2dbe63bc864ac5c5963a68b1c5c2b325c75a6cb1f88e4f8bead4b9d6e63a68b1d9c2b339c75a6cb6f88e4f8bd2d43175531db4d864e1d994632d36597cc71817a9ebc98d75d062a38567638eb5d868f11de3712415171beaa0c5060bcf861c6bb1c1e23b3e2d46a4ee3fadaf8316eb2d3ceb73acc57a8bef18efb9a4e2625d1db45867e15997632dd6597cc7a74597d431756d1db4586be1599b632dd65a7cc7a7c5f0d433b13575d0628d85674d8eb55863f11de37967aabd585d072d565b7856e7588bd516df319e77a6ee5facaa8316ab2c3cab72acc52a8bef18dbced479e7ca3a68b1d2c2b332c75aacb4f88ef1bc33a5c58a3a68b1c2c2b322c75aacb0f88ef1bc33751c595e072d965b7896e7588be516df31c645aaed5c56072d96597896e5588b6516df31ded74ab59d4beba0c5520b8fabf11aa2b4586af11de3f548ea1edf923a68b1c4c2b324c75a2cb1f88ef15951ea1c7c711db4586ce1599c632d1683ef03b1fb4ef7e7161fd217eb32438b4228f36d49fa57fa6245e928ebc07e65589745b1d725ddaf6c61445d16415da44c6187dabab40c9c8cf753eea8aea99859007552ebfdc4525729d3aa43ad2e099d4fc036390cba9d61f9bf4c05c67c12f2a29faaf37bf1d73915abef026712fca0ef77803526df9dd177814ee247ec85903fbd436d5929277a88d6c2aef691f7751ed9cde5161bcb154399f72df54f06f1d6ff3d83e73d83596d936288338923376d579ae9fd088d2e038da40cf6d9fbc4118fd9875038c49f2a23dbbfb95106fb504a99f3a08dc27ea552cf447074bf49476d5967649775cbbcf82b06db016034eba8e2631ff4fd94b122641c0965937121bac07aba1b3655d71e8eea2abe64dd32df0318659c8aeeb9672cab2b63378351f1f472a0198ebd2153a6e3452fe0e9e980c7513d53c7a10aa34e3d8c3a1543197cb7b1c2413d0bc0afac5be62bc0b78b6d8e5ac831f962438b42ac37b46799749475a8f8ed6ea94b1fc77591754bbbd42707be2b0ddf5d0ddf89e0c8ed1c0499f7af4a60eeed8059adb76ffceb2dc5f3368929f1d315ead40f3488ab4eb82e39cfeb67685b08f9fe709e27e5a4ac1cbf845dc5b26c4b643797eb652c570c65fa58ea9f0ce2ad7f5f83a7afc1acb6c90d706ee7607f48c5401f8343e6bb82767d23b4eb03da49193cfe7573a45d6f8347e6bb018f9ce354804dce15843f01ffef92036eb3ddabb0708b0dc789eb6661ec1a3f63ea5ca79bc128f35d81516cbd81a7d29166e6b6bed8d0078fcbcd8d32b26c219479088e8d094b59b5df5d58505bafa6da1edbbb63ba4d6fee402f1ca731007d0243c300f4927a3673c0d33aa81dab71e2a49a09431f1c7ec7f0f4a347412b3430f1b7c0528d2660c37c538b2d088e1c92b2106c32246533b0353164c1a130a5bc0c69e7422ed443d65d6870b60496387de3709e32650a9d16c0e3229455e8c8909e3a74ee99306ad2708c8f6606677d6247fdaf69867251eb72b51dcc7d2209f3660c163af2df14ea9b8479f1a7b68d0cad3a6ee8b087fb4d7870f298e163274d44a1cc1d1bf305c1911bc0fc8d12dcd54e87018015c6c6a199512f6c30e47fb2615ac7cf598e63e69ada04e04fa6d6a05b2b07baa9f5cbd8b7c3868e1e7ddbe4aad1a3865d3379ecb049a36ac6e2d66c692817b5a5e5ffcdc1666be2b1ac9ab0d9c2655b586cb60947196e09363972b5029bf0b4065b53c84b7973cb3809d70b60fdb24ba9ff29719ae98ab7086a43400ec7aa5d55fbaf3a95539f9055a7426a6863b539d5d0c5ea8ea11a9a587dc54e0d3dac861a56430b9f11a4870e5643059f1da48702565fbb2809d243fb9e17d40eddaba6c3c0f9bd203d34afba4d7351903eed5243eb760cd243e7aa5b979d82f467ded4bbf5eaf45ddd1650a7bcea124f9d7eaad34e7579a16e5fa85b59ea944e9d2eab534175faa62e47fa6aadfb85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bb82f4f0ce7707e9e1d7d5f0cff706e9a1a1ef0bd2c346df1fa487947e20480f373d34480f453d2c480f533d3c480f61fd60901ede7a54901e26f7e1203dd4ae1a82776c901e0e5b0d93ad86cf56c3fcaa2181d590c26aa861352cb11ac2580d81ac86467e3c480fb9ac866c7e2a480ffb3c354ccf84e9d9303d17a6e7c3f442985e0cd2c383ab61c3a705e961c6d5f0e33383f470e5b383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f06f86e9ad30bd1da41f49a84731ea1185bafdaf1e83a95bd48b82f4adf32541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a7f90be2d7e30483f2a55b7c3d5a301158feaf6fd6761fa41987e18a61f85e9c761fa49987e1aa69f85e9e7417a586335dcb11a2e590dadac8661564336aba19cd550d06ad8e82f82f4d0d36ae8ea3f05e921b1bf0cd35761fa3a480faffdd730fd2d4cdf84e9ef61fa4798fe19a67f05b54369636371866e61f4554a3074d2a4e163c64d2a9954533266f2e849a3c68d7eac64caa849234b6a1e193e61c4e89a29b8f00ff5c2320e78bf0913863e56326a6cf5f0474b6a264f2aa91951525533796cf51107ea7fea85ce3adae3d0eaea6867fffe5d48ff6f3d9db6d26d9f8cb07e7de6bab5695a0f414ea8cf42dd9ad6af4213f4514a2e67ef4c9feb964c1c5d33a9a4b4646cf8373cb8d64c195edda904ff37311479e2a4928993864e9854326242cd9892ce9d70bd4fb7ae4725fea3b51b985667d44f9c16fa5b4af50ab19de7d64381cfcfad1fe9dfbf0be9bfd5d369eac09b6d0d9bd767a14b4aea47585e1229cbc4c95593260c1d36297ae19edf65e1bef5a9e62df5ace67fd5c759d30ef558a84387fa11f6ad8fb35159380bfe3f244cae11d44d06009b2d6c6f00000027cc1f8b08000000000000ffed9d77701cc795c667911856581024981324db1423b8586430813953a6242b072650a44512140925cbb2244b72ce395b4e6739e77c9673ce39e7ecba2adf3f57bef255b9ae7bb69ff1a139b3c6aee6816fb06faa1eb6e76defbc5f7ff3a667b67b7690098acb9f8d655cb9d6d8638273177a7fc0bde61fddd29ee0b6f29c9c999470d6a484b336259c7529e1ac4f0967434a3827a58473724a38a724c899013e2edea929e3cda68cf782201d79db9812ce5c4a389b52c2392d259ccd29e19c9e12ce1929e16c4909e7cc9470ce4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e29470b6a684f3c294705e9420e70ae0a431f2c7bad7c7b9d725eef562f7bad4bd2e73afcb5d1bebdcbadde64a63ab8cb579efadb6ccc6ec6079c17bafc358a7b12e63ddeebd56f75e8fb15e637dc6fa8dad31b6d6d83a63eb8d6d709a6c34b6c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd825c61e6f6cbfb14b8d5d66ec72634f307685c772a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b8d9d3076d2d8296343c64e1bbbc5d81963678d0d1bbbd5d86d9e66b71bbbc3d89dc69ee471de65ecc9c6ee36f61463f718bbd7d87dc69e6aec7e630f187bd0d8d38c3dddd8338c3dd3d8b38c3ddbd8738c3dd7d8f38c3ddfd80b8cbdd0d88b8cbdd8d84b8cbdd4d8cb8cbddcd82b8cbdd2d8ab1c0b1d08af36f61a63af35f63a63af37f690b137187ba3b137197bb3b1b718fb0f636f35f6b0b1b7197bbbb177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fb4f639f34f688b14f19fbb4b1cf18fbacb1cf19fbbcb12f18fba2b12f19fbb2b1af18fbaaa7f9d78c7dddd8378c7dd3f9bee55ebfedead231ff1df7fa5df7fa3df7fa7df7fa03affe0fbdf51f79eb3f76af3f71af3f75af3f73af3f77afbf70afbf74afbf72afbf76afbf71afbf75afbf73afbf77af7f70af7f74af7f72af765e6dc5cc62797230b20c0409f5499d837d765c9dc4f6e7edec9c50ad7b8f5e5b9dbfceadd36bc6f9ebdd7abde76f70eb0dde7626bbf5c99e3fe7d6739e7f9a5b9fe6f9a7bbf5e99ebfc5adb778fe0bddfa85e0cfbaf78a0d2bbe585fad7365c047f95903be7ae7ab055f036d0e7c939caf1e7cb47f1bc037c5f926816faaf34d065fd6f9a69096c62e70be8120a95cc91fb4db6d4c7abb6e2e22973cef21bbdd2626de69c9f31eb6db6d66e0b5f931dd6dab11f26686f3e5c0d7e27c4de0735dd0bf8e39eb9be57ccde09bed7cd3c137c7f966806faef3b5806f9ef3cd04df7ce79b05be05ce371b7c0b9d6f0ef81639df5cf02d76be79e06b75bef9e0bbd0f91680ef22e75b083eea2f1781efb1ceb7187c746dd70a3ebacebb107c74cd7791f3d97e627206e2393ff551613cea9fc1f738ea9bc1b784fa65f05d4c7d32f896426cf22d837e857ccb9d8ffa28fb5ebf2b0f04491d1385f0185e93f476cd96ed76d725bfdd700e6c7d30a2f500c459035a6d70e504ef0f69c7d8741d4371c85f07e59d5097ea911e749e2176dbefaf75e50d253ed7ef7d2e0775d646b47f2048b6fdeb3c9e751e733db49f29678f6ace8e79293b67af84ba7eeed135cf44ccd93dc0917cce767468ce8e79293b6707a1ae9f7b74dd3b1173f61ae060c8d91e9e9c2de435678be36041109d7bf4dd6722e6ec31e0483e67bb3467c7be949db3f7415d3ff7e8fbef44ccd9db8023f99cede9d16b83312f65e7ecf3a1ae9f7b3416331173f601e060c8d943dacf8e79293b675f0b75fddca371c18998b32f028ee473b68f29673b346783e29c661044e71e8d514fc49c7d083892cfd9c33a3e3bf6a5ec9cfd18d4f5738fe64b2662cebedb95ed3cc3b7dc3cc302f07ddbf916026ff2b97da49d29b7db35b78bf77a0441748ed2dcdd44cced475cd9e6f177e1de03f27d8fee4b00dff79def22f0fdc0bb6783e918e8d66360ec6d2af718f819d4f57399e69127e231f06de060c8d91ecdd9b1b7a9dc9cfd0bd4f5738fee69988839fb4be060c8d95ecdd9b1b7a9dc9cfd3bd4f5736fa92b4fc49cfd2f57b6d70b3f71d70bcbc1f753e75b01be9f39df4af0fddcf95681ef17ced706be5f3adf6af0fdcaf9f2e0fbb5f3b583ef37ce5700df6f9daf037cbf73be4ef0fddef9bac0f707e7eb06df1f9daf077c7f72be5ef0fdd9f9fa9ccfde9347f75e7dd1f9ecbe258d068264f72ddd6349dba6f595e310bbc98bdd348eb19bbdd8cd11b15731c4ce420c5a32defa009457f1f2e473c083b156271fabc3b6bd2d187bdb57034f9ea1ed598831169e3cf0b427cf139e3f0bc96f37dcc76d9ea65988d506edea6068570662d1b6699de2e5c087fd7747046367f28c850cc4a26dd37a2730920fcf27745ea7e3c79e0f97644678198ea5f09a88e2d1f39f886335f8a9ce375b46d8963bb646781fcfaded9e8f292fc3bca058b46d5aa7788dd09ef6f1672c8c9531ef3172f511198845dbf663e3f1be6afc351bd37ecd81ef3cf449854afba446601b8feb94b87d2d2536c7f92a0331a86f23cd0be0a73ab3dc0f126cdfb61dfa5d86e3af50eef51bf607c9e771218fc7f558783a8087e3d8673a5ef378deff67906cae75795ab57b5ae5a04e27e8d7c5a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b9cdfa47a2b853092af003c1ce3fce133a0dcb668fb765ee7c730af93fcbc45218f7396748fe132afcd7550e7af9991ba3f87f9747f6e10e73457f26a37a6fb2c1a8373e76239e710e3e681a3e62f5b138b5d38cc35df66ef51b3cf216bf3745d19a129c37d2aa334cd789ae27d8a2b3c1e9ba7736b47d838e6feca9d8b44ada89ce4dc1ede63c0bb5f8afd07e5424d30baffc0f34c77e2b147cf61d27c79b717bb0eeafc6f6664dfd0bda8f4bfeefc7b9e6c9d1e6fdbf49965e0eff1b63dcd7d9638eabdedb7c167a9ceff419ffaba9ae05f9a71dcff81fd72006dc56500ca386f9efc79b8388fdf51064f17f070f4334cd71b793c06929ec7eff1b48aba8ea13adda05f0f837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff39c9a91b8dcf37034e7b4dc6b731dd4f946cd48dd17b8726370eefd0e71fb92613eafe4bea4788dd01e9c0be2fa3d77a7c7d319a105955b138b5d9cc74f5ee39179fc0e4fd74284a65cc72bceb1a2a678bcb67b3c3837da189c7b6f4916b6331ef70ec5e505c5c363a9137c54c6df4773ec673c97f8f7f5503c9cbf7ed8693b2de0daf7853c67bfd10b6d1a08cecdef3aa8f32ee8fbdee3ca780f07de3bf248c4fbb4949aa726fd589e65972fcefbae01ce018883b1d7026b42b1db3176c619c5217f1d943f59335297ea911ea435b1db63849e0986ecfee7dabdcfe5a04e5f44fb078264dbdfeff1f47bcc769fbc1ff2ec1138ff73f5497d311a2d038da80e5e0771dd93e7f791fefd8d78df5e835707af59a8ce17a18f8abb7f34ea9e43aef358dc3d8751d7c65dc0e8b7d1bfcfb3daefd3fa21f41749dfa7f543c821bc4f2bf0b6bf1cb64f5c0d41fcb985eafcd4dbbe7f4d4e9fc1fbc0a8ce2fa0bf6872f72c3606e75e7fe33d53e3f1fd2aee3e698a87d735786cffbbb65be65ea83f902033e604b2e07502d5f993b7cf7a62b857477cf6af319f25ade83954f8fdc5d7cfead0079f19484487e231dfefb585f2ba0fda4275fedbbb064cfebaa5780d987c5b475f93503fd019d156aaf33f70acfd1daef1683fe1f78e86da73dfa7a5d43520e967db3cdecf07c6d8129e0f5c5f3b52d77fce2f695deef381bbbdcf497c3ef03f20cf1ae03e74aebe7a6d8c46cb4123aa83bf0da2f3083ecb37ea1cc3756f7fdc3926ea1994d83f37d58e3f9b3fae16758d4075e8b3788dd0e298a7399dfdbafe78219d2f93bc6f187f2bd10671f1b7126d4c7ae641b70158c7eb82f3193bcf143bee99d3f971881df7cce9f188ddecc56e1ec7d8aab96a2e497386672287bf3fc36796daa5d4752931e4e073352960ac4d01635d0a18eb53c0d89002c64929609c9c02c62929609c9a02c62c309ecf733b833e854af5e1da5fa5ae353036c3ff2e2994fbff3b98ff974ac96b1f8ccdf09d2ed4625530762df07b1ec7b31fcafd5f2fc480ffbb607a0a1867a480b125058c3353c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89a02c60b53c078510a181f9302c6c7a680f17129605ca28c8930aee0652c54ca687938fee7dfa3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e697ba5cf8dc37b4b78ff27dca37bb61dc7bd23e53edbaed4ff5b65622c54cac8751f3bfe8e672c3cf8bbc8a8dfd63030162a65e4fafd0bfe466f2c3cdda0595784660c8c854a19b9ee952bf75e4ebca7bf3b423306c642a58c785f75823ca1663d65f0f482663d119a3130162a65e4ba2f390b31c6c2d3079af54668c6c058a89491e9b76da1667d65f0e06fc0fa223463602c54ca6879d63069d65f06cf1ad0ac3f4233498cc893f473b2fb236271fc66b0dcb61303324e4901e3d41430e27d121cfd57a9fb24fa79f52954aa0fd7fe2a759f04c666f87d4ca805fe1ee2df69b18e97a7e47d12187b3d9316f87b957fa7c57ae0e1f8fd4c16628c85871872f0b9e929609c9102c6961430ce4c01e3ac1430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01237e5765b8562cf9fd65fd048f1df75d65a2c78efb5e32d1636b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae79262a7618c5f19271e23f2b426c793c7b663ac01016d1f88e0c930b51d636d14d07662481be3861430ae4901a3ea58bc07b11246cbb389896763193c9b80673313cfa632783603cf96e479c29cda5c060f31e4e0736b52c0b821058caaa3ea28895175ac1e1d955119955119cf07631afa70654c453e162a65b43c5b93e70935db5206cf56d08c3ed7cecb58a894d1f26c4b9e27d46c6b193cdb40b3ad119a3130162a65b43cdb93e70935db5606cf76d06c5b84660c8c854a192dcf8ee47942cdb697c1b30334db1ea1190363a15246cbb333799e50b31d65f0ec04cd764468c6c058a894d1f2ec4a9e27d46c67193cbb40b39d119a3130162a65b43cbb93e70935db5506cf6ed06c5784660c8c854a192dcf9ee47942cd7697c1b30734db1da1190363a15246cbb337799e50b33d65f0ec05cdf644682695714d0a1837a4809159c742a58c96671f13cfde3278f601cf254c3cfbcae0b904781e9f3c4f98539794c1430c39f8dc9a14306e4801a3eaa83a4a62541dab4747655446652c8f7120058cbaaf95512a23c3f7ab92bfa1b96482c76ef262375549ecb8dfd04cf4d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e6b9a4d8fb938f5d28f71933fb8187e399374cedccdbed5eeab6f5cf04f5b35a5de6697589a7550eea5c0afa5dc6a05f06e2d2b6699de295cb7cb10066a6d805dbbf4c81f6538c0d9e1e36fee54c6d8febeb2f9fe0b1e3fafa891e3baeaf9fe8b135cf35cfab21b6e6b9e67935c4d63cd73c97121bcbf5c1c8753b3dffd46ee309ae5ce7d69195fc54e7f1938aafd3023d863862eb31a4e78a6a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9ecbcbf31cbc5f330e3c81c71394e059248c678e309ee9c278a608e359268ca75618cf7a613ce3713f5f393cbb84f16c17c6d32b8c67b1309ee5c278e60ae32908e399218ca74b18cf54613c5b84f1d409e3d9288c272f8c678f309e25c278e609e36911c6b342184f56184fbd309e4dc278560be3592a8c67af309eddc278fa85f1ec10c6d3278ca75b18cf7c613c1dc278660ae36913c67381309e46613c5b85f13408e359258c679f309eb5c2781608e399258c27278ca74918cf24613ceb84f1ec14c6b34d184f8f309e85c2783a85f1cc16c6b35218cf34613ccdc278360be3992c8c272380271b9cfb4cb22cbcbf1f7c35de67edf540f3cc91f7af70fe1af8cc95ae5c1bb1ed2bc047bf0dbf32e2b3a8d315d0960157ce3fba25d409630dc03ac56b048e2b85f04c16c6b359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278b609e3d9298c679d309e49c2789a84f1e484f1cc12c6b34018cf5a613cfb84f1ac12c6d3208c67ab309e46613c1708e36913c63353184f87309ef9c278ba85f1f409e3d9218ca75f18cf6e613c7b85f12c15c6b35a18cf26613cf5c278b2c2785608e36911c6334f18cf12613c7b84f1e485f16c14c653278c678b309ea9c278ba84f1cc10c65310c6335718cf72613c8b85f1f40ae3d92e8c6797309efdc278d60be3a915c6b34c18cf14613cd385f1cc11c6b348184f4d040fc3ffbf0c79e8fe35da36adef17129b613f84fff7f32aa6365dedb655efb64bfc14af0eea5ce33a0a7b7f157e96b8fcfb0df1dc7435687435535b687f64bcfdc31d1befab0c8021f0f409227838ee47656ae7a83c4cf0ffcfe6ad56d7785af9fb2e0775ae02fdae61d02f2ab7ff750c000f5de7106b16eaad17c248becb9979b2d0665a4a1d03d7000fc731c9d4ce3057aff5dab43e4277aa83b97a2d433ba38e1d5abf167836ba32b166a1de46218ce4bb9a99270b6da6a554ae5e0b3c1cc70e533bc35cbdce6bd3c608dda90ee6ea750ced8c3a7668fd3ae0d9e4cac49a857a9b843092ef1a5e9ece2cb4999652b97a1df0701c3b4ced0c73f57aaf4d9b2274a73a98abd733b433ead8a1f5eb613f28b33247315b1efa9d0eb166a1de66218ce4bb9695a7339f8536d352aa1fbb1e7838fa7926ddc37eec06af4d9b2374a73a98ab3730b433ead8a1f51b2262b706c96a71e318b4b83182e7c671d682e295cb7c550a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7f161569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d5b93266cb43cf4522d62cd4db2284917cd7f1f284bf0bda128c5e32defa00946f049eeb19f4616a67780ff901af4d5b2274a73a787c1d606867d4b143eb07603f1c2883f9861432abce95315b1e7afe38b166a1de56218ce4bb9e9727ecc7b606a39752fdd801e0e1e8e799da19f66307bd366d8dd09deae0f17590a19d51c70ead533c6556e63866cb43ff078858b3506f9b1046f2ddc8ca53087fdfb82d18bd94eac70e02cf81c4798afd1883ee613f76c86bd3b608dda90ee6ea218676461d3bb47e08f64339cc37a4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9f2d0ff8321d62cd4db2e84917c0758793ac27987edc1e825e3ad0f40f910f01c4c9ca738efc0a07b38ef70d86bd3f608dda90e1e5f8719da1975ecd0fa61d80f139df98614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5c9958b3506f871046f21de4e5099f7bb02318bd94ba6fe730f01c62d087a99de17d3b47bc36ed88d09deae0f17584a19d51c70ead1f81fda0ccca1cc56c7976ba32b166a1de4e218ce43bc4cb13f6633b83d14ba97eec08f070f4f34ced0cfbb141af4d3b2374a73a98ab830ced8c3a76687d10f683322b7314b3e5d9e5cac49a857abb843092ef302f4fd88fed0a462fa5fab141e0e1e8e799da19f66347bd36ed8ad09dea60ae1e656867d4b143eb47613f28b33247315b9eddae4cac59a8b75b0823f98e30f364a1cdb494eac78e020f473fcfd4ceb01fbbc96bd3ee08dda90ee6ea4d0ced8c3a7668fd26e0d9e3cac49a857a7b8430926f9099270b6da6a554aede043c1cc70e533bc35c3de6b5694f84ee540773f518433ba38e1d5a3f063c7b5d9958b3506faf1046f21d65e6c9429b692995abc78087e3d8616a6798abc7bd36ed8dd09dea60ae1e676867d4b143ebc781679f2b136b16eaed13c2483eecc7f631f1347a3c8d115a4cc4d84d5eeca62a89ddecc56eae92d89ae79ae7d5105bf35cf3bc1a626b9e6b9e5743ec6acd35d5bc3a35cf9c47cd33e751f38c6a2e52f37f2617bb2b178c2c35108b617cae7d2c638ec8b34818cf1c613cd385f14c11c6b34c184fad309e5e613c8b85f12c17c63357184f4118cf0c613c5dc278a60ae3a913c69317c6b34418cf3c613c2dc2785608e3c90ae3a917c6b35a18cf52613cfdc278fa84f1740be3992f8ca74318cf4c613c6dc2782e10c6d3288ca74118cf2a613c6b85f12c10c6334b184f4e184f93309efdc2782609e359278ca74718cf42613c9dc278660be359298c679a309e66613c9385f16404f06483737fdb81bf27a8051fdddfbf0f7c4f74e5fde0ab898841db390e3e1acfa56dd8f3d58299e732d4c0676e8ee07a62443c8a7373c467c743778c3500eb14af11386e16c23359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278d609e399248c67bf309e26613c39613cb384f12c10c6b35618cf2a613c0dc2781a85f15c208ca74d18cf4c613c1dc278e60be3e916c6d3278ca75f18cf52613cab85f1d40be3c90ae359218ca74518cf3c613c4b84f1e485f1d409e3992a8ca74b18cf0c613c05613c7385f12c17c6b358184faf309e5a613ccb84f14c11c6335d18cf1c613c8b84f1d444f0ec67e2897b9ec27e01b1edb8375d0bd2985816de1f8fdf29edf71869fd1830920fefd3cd33f1c43d83222f20b6d5623594ed9285f7f177265c3995f718693d2aa7f03ecbd54c3c71cfed582d20b6d582e606e81e802cbc8ff75573e5d46a8f91d6a372aa999727fcff01ab82d14ba97b8df098e3d8874cedcce3f197e03334229f91bccad32a0775c6e3bee2b8fe80e229b332c7315b1e9afb22563c9f8dc7ef96c6c218757e65e009fbc7b660f452aa7f3c063c1ce70fa67686fdd809af4d6d11ba531dccd5130ced8c3a7668fd4444ecd620592d4e8e418b93113c27c7590b8a572ef3fe14324bd0d9f2d0bd9ac49a857a2b8530922fcfcb13f68f2b83d14ba9fef124f0709c3f98da19f609a7bc36ad8cd09deae0f1758aa19d51c70ead9f82fd500ef3891432abce95315b1e9aa321d62cd42b086124df31569e423e0b6da6a5543f760a7838fa7926ddc37e6cc86b53214277aa83c7d710433ba38e1d5a1f82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0ffd769858b350af430823f94eb2f214e71d3a82d14ba9798721e03995384f71de8141f770dee1b4d7a68e08dda90ee6ea698676461d3bb47e1af683322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf40c7962cd42bd4e218ce43bc5cb13fe6eab3318bd949a77380d3c1cf3324ced0ce71d6ef1dad419a13bd5c15cbd85a19d51c70eaddf02fb419995398ad9f2d0b30789350bf5ba8430926f8895a7387fda158c5e4af563b7000f473fcfa47bd88f9df1dad415a13bd5c15c3dc3d0cea86387d6cfc07e2887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1e9d2d0ffd4f4362cd42bd6e218ce43bcdcad311ce3b7407a39752f30e678087635e8649f770dee1acd7a6ee08dda90e1e5f6719da1975ecd0fa59d80f139df9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426e589e1e5726d62cd4eb11c248be5b7879c2e71ef404a39752f7ed9c059e330cfa30b533bc6f67d86b534f84ee54078faf618676461d3bb43e0cfb419995398ad9f2f4ba32b166a15eaf1046f29d61e6c9429b6929d58f0d030f473fcfd4ceb01fbbd56b536f84ee540773f5568676461d3bb47e2bf0f4b932b166a15e9f1046f2e139ae8f89a7d1e3698cd0e27cc5b65af4bbf205ee350beff7032357dfd2e731d23ae638f91a81a79f89a7c9e3698ad0e27cc5b65aac85b25db2f0fe5a60e4caa97e8f91d6a372aa0978d632f1347b3ccd115a9cafd8568b75ae3ccdbd66e1fd75c0c895536b3d465a8fcaa966e059c7c413d727ad1b87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c478563a7142300065c06a08cdf1538ae3d99da998ffa3eb6ce6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879661662dc6730cb2df6b93b431c872994fa4905975ae8cd9c6be2df9d89d592f36e913783cb4dcc6ac05533bc3fee0f6205a638a97833a98a7b733b433037169dbb47e3bec8772984fa4905975ae8cd9c6be23f1d8c567b3636cd227f07868b983590b9e7616fb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01f945999955999955999955999955999955999955999955999955999955999955936b38dfda4c46317c7ef3136e913783cb43c89590b9e7616c7efef0aa235a67839a883fbfc2e867666202e6d9bd6ef82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271f3bfc3d0ec6267d028f879627336bc1d4ce70fcfeee205a638a97833ab8cfef66686706e2d2b669fd6ed80fcaaccc51cc36f653128f5d9ccfc3d8a44fe0f1d0f214662d78da59ec0fee09a235a67839a883fbfc1e867666202e6d9bd6ef81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c3d3adbd8f7261ebb231cbfc7d8a44fe0f1d0722fb3163ced2c8edfdf17446b4cf1725007f3f43e867666202e6d9bd6295e35309f4821b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80d1bfba9c9c70e7fcf8eb1499fc0e3a1e5a9cc5a30b533bcffe5fe205a638a97833a98a7f733b433037169dbb47e3fec076556e628661bfb0186d8592f36e913783cb43cc0ac05533bc3fee0c1205a638a97833ab8cf1f64686706e2d2b669fd41888d7a27143bbc079262d4b857eb7b9a2bd782efe9ae5c07be67b8723df89ee9ca0de07b962b4f02dfb3a13de47b8e2baf00df735d791df89ee7ca6bc1f77c57ee07df0b5cb90f7c2f74e561f0bdc8956f05df8b5df936f0bdc4956f07df4b5df90ef0bdcc95ef04dfcb5df949e07b852bdf05be57baf293c1f72a57be1b7caf76e5a780ef35ae7c0ff85eebcaf782ef75ae7c1ff85eefca4bc0f75084ef0daefc54f0bdd195ef07df9b5c793ff8deecca53c0f716579e0abeff8032bdbed5952f00dfc3aedc08beb7b9720e7c6f77e526f0bdc395a781ef9daedc0cbe77b9f274f0bddb956780ef3daedc02bef7baf24cf0bdcf956781effdae3c1b7c1f70e539e0fba02bcf05df875c791ef83eeccaf3c1f711575e00be8fbaf242f07dcc951781efe3aebc187c9f7065dcbfffe9ca0f808ffa9507c147fdcad3c047fdcad3c147fdca33c047fdca33c147fdcab3c047fdcab3c14779f71cf051de3d177c9477cf031fe5ddf3c14779f702f051debd107c94772f021fe5dd8bc14779f712f051debd147c94772f031fe5ddcbc14779f70af051debd127c9477af021fe5ddabc14779f71af051debd167c9477af031fe5ddebc14779f710f828efde003ecabb3782afd595df04be0b5df9cde0bbc895df02bec7b832f6338f75e5b782ef71aefc30f8a82f7c1bf82e76e5b7836fa92bbf037ccb5cf99de05beecaef02df0a577e37f856baf27bc0b7ca95df0bbe36577e1ff856bbf2fbc19777e50f80afdd953f08be822b7f087c1daefc61f075baf247c0d7e5ca1f055fb72b7f0c7c3daefc71f0f5baf227c047e771ea67ecf16c8f41d28134b23e6a735b445bc83719da3210247b4d47b168dbb4de018cb40f0ae3cf58182b63bbc76879ba1834c3bca2a5d4f78f2ee0e964e0616a67f8fda3db6b5387d7a61cd4b918dad9cdd0ce0cc4a56dd37a37c4e6d8e7a845bddbee524f8b3aa8f3077792b3e7ce523ad2366cfe1622dad2c7dc16da36f54b7de310bbc78b9df762637f4c4ba9e3ab07987b1998ed76fb93df6e787cad71dba29ca2387968d35ad020a93661ec8c338a43fe3a28ffa365a42ed5233de8fc45ec3697695f22bbffb92eef7339a8d317d1fe8120d9f6f77b3cfd1eb3dd277f6b19e160381ec21ce8f338683d0fdaf5c768d707da511d3cff1598b4ebf5787abdd89687ae71bac147d70ac48fd7596de3c0edf77bdd11dce4eb01c6a86b9df6e4194b5eebb40323f97a81a78749337f5f2ff5f4c1f3728357873e5b07759adc97bd69c1e8ef1f54d71e774b3223eda2efe0ff0c92edd31b18f4c2f18100f4093c0d03d08bda59cfc03335181923383b3c74e6e04d83970e1e3c9201b43a0f135f3311cda8011f966b237c41307a2804876469280487646b3c59700886eadbaf52b65934dc3078f2f8f0134e0d9e3a7ce6ced3c38347f60cdd84d4f51e3d92c6b50049d147cbe46064d066204836791abc58a5926732bc4e62e0616a6778d29be2b5a9c16b530eead4c37b5318da9981b8b46d5ac70160f26176d2fb386150e3b505b3780abcfafb36d10651c0c7c0f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b0d8aa35e1701cf1781d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd5913d23da33a1fd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d99596f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31f6f8a038a27ca9b1cb8c5d6eec09c6ae3076a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b83e21d1e278d9d323664ecb4b15b8c9d31763628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee0d8ab32a7676c4ce86d891703bf26d47baedc8f63382e2c8b51da97e76501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1414474eed48a91d19b523a176e4d38e74da91cd8783e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee93c61e31f629639f36f619639f35f639639f37f685a098935f32f665635f31f655635f33f67563df30f64d63df32f66d63df31f65d63df33f67d633f30f643633f32f663633f31f653633f33f67363bf30f64b63bf32f66b63bf31f65b63bf33f67b637f30f647637f32f6e76064d41e3b8abfbb151a413e383c3c78f2f470ebf050ebc95b4f0c1f3f7de2ced6db8f0f1f6b1dba6df0ccd11343b7e387dfeaba261a1edf78e6ccc13b5b8f9f3a327847ebd0adc3ad43475b0f0ddd7aeac859fcd017dc87169c1bf1e09123f1c17e50f328487f5261d03fbacfd1c4c3ced26dfb4b2582fcad920fcda8adac4197b8330b7d2bbdac7815d77af6c4d0706bbef594f97bf084f9cce091b6567cefac11f9ec70ebd9e18367865b8f9e193ad9dade86dbbd7a4a058df87d4b051fcacd1c7bcb83ff079bac954d69010400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x28f6931da37e7dcba1db1327de9c81d93d6dbbcfd809b7503e43a298a2373fe3", + "id": "0x25ff42e7b5351646829b6ce29c6a64660cbcc9d81954e67ab57d47dfbc096613", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x13b5b578e8f823e8816a172573e197816096c5b3097293a04acfbecb026c0744" + "publicBytecodeCommitment": "0x2152b1029338584a8d43bbf80c6da9cf988c33c54e1f9b86741a2fa94986fe6b" }" `; diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.ts b/yarn-project/circuits.js/src/contract/artifact_hash.ts index e51852a8aa6..a51a609ccfd 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.ts @@ -35,6 +35,8 @@ export function computeArtifactHash(artifact: ContractArtifact): Fr { const unconstrainedFunctionRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.UNCONSTRAINED); const metadataHash = computeArtifactMetadataHash(artifact); const preimage = [numToUInt8(VERSION), privateFunctionRoot, unconstrainedFunctionRoot, metadataHash]; + // TODO(miranda): Artifact and artifact metadata hashes are currently the only SHAs not truncated by a byte. + // They are never recalculated in the circuit or L1 contract, but they are input to circuits, so perhaps modding here is preferable? // TODO(@spalladino) Reducing sha256 to a field may have security implications. Validate this with crypto team. return Fr.fromBufferReduce(sha256(Buffer.concat(preimage))); } diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap index 9c3ca6a483b..2575fdd8f35 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Header computes empty hash 1`] = `Fr<0x124e8c40a6eca2e3ad10c04050b01a3fad00df3cea47b13592c7571b6914c7a7>`; +exports[`Header computes empty hash 1`] = `Fr<0x2a45c01b78a6b9a2392b7490966b41f47e5d9ac95610fa3eabe99d9aec7f6ad0>`; -exports[`Header computes hash 1`] = `Fr<0x1d9b824f3561e706d9e85fde89a60a1e5c25dff839167cba7366ca8f6ee96890>`; +exports[`Header computes hash 1`] = `Fr<0x26c31c3eb93ca2ac5d43166895960b259839bf6947f23f77cea1e729892f5ad9>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap index 1855459d99e..0f21d438752 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x134b57e317f1554b9c4f547e617338fcc8ff04c6d96a278f1752b26a462c5d25>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x135b1d61b12d391c14ff7aaae8bcff574a1e22afa20a5b59c67c1418d77fef72>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0827f66d5441052dd5a2ce06f346816f02173bd4ed0dc3eb9071e840de06a11d>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0979cafe39f17f08afd21e9046cf804d70775af7513e23640ead3b7f95e0e163>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap index f99bdd2000a..4f64ca399c4 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x2b5ba01a6b73b68b4f44196e2dea49afd4076333e2dee8eddc9186e080f18201>`; +exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x0f16478dc1731c940b04c312d322697f6a3bff523d2660d896426b2ab3af9598>`; -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x25f066a8adb3889b9ebf162d7af91352a77200965cbc7900831b745e31342fb4>`; +exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x11a3513c2e9e3301a8aad659646c9314d9207e8fe3574540b4e02ba1ddcb7a69>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap index c7aa3aa0744..d676ab14aea 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x0f22ddeca80a2c6f455165f1d2d1950c5e1b772bdc312742d1de089b424f0f5f"`; +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x05e9e448563aa811c209cc557136ac56b55f9f2f31ee54d41b697389fd45dc1c"`; -exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x02e15f4157b5e2cb0a7ec3dfec18c6812ef16e1da319b364e5a11e337dfca414"`; +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x141bbf6bc30f0a19640983354528288239b68edd5c1edd9955a007801230d7b6"`; -exports[`PublicCallStackItem computes hash 1`] = `Fr<0x279f5bc054922565defcae4895f4c782fad47012f36dae267fd9f8d35ab5cc95>`; +exports[`PublicCallStackItem computes hash 1`] = `Fr<0x0a9961096ae423e5c4bc1175bb191b8c2b2ad63feda7ce5599842909c09d9973>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap index 9c07ecf42ea..ac66f2c8c30 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCircuitPublicInputs computes empty item hash 1`] = `Fr<0x083ac560a513d670a7f50f0a3052d42cb9816b7b643e62025b8278652ad637ab>`; +exports[`PublicCircuitPublicInputs computes empty item hash 1`] = `Fr<0x0f1eb4e352e8dab6cbab3c63b6d8f3cd2cd90cc7ae5ff142e4dfa2b3e28e01c1>`; -exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x26612d7a1afd04b2023d9a766f7c44042ebdfbd606e4b347fd4c201040c53658>`; +exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x292de5dfe34d2970781cc583f2273f880ed55a98bd7f8216bbb1297c2f29a2cc>`; diff --git a/yarn-project/circuits.js/src/structs/content_commitment.ts b/yarn-project/circuits.js/src/structs/content_commitment.ts index ac17d1b86f5..8b047bf2365 100644 --- a/yarn-project/circuits.js/src/structs/content_commitment.ts +++ b/yarn-project/circuits.js/src/structs/content_commitment.ts @@ -1,5 +1,11 @@ import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, FieldReader, from2Fields, serializeToBuffer, to2Fields } from '@aztec/foundation/serialize'; +import { + BufferReader, + FieldReader, + fromTruncField, + serializeToBuffer, + toTruncField, +} from '@aztec/foundation/serialize'; import { CONTENT_COMMITMENT_LENGTH } from '../constants.gen.js'; @@ -25,9 +31,9 @@ export class ContentCommitment { toFields(): Fr[] { const serialized = [ this.txTreeHeight, - ...to2Fields(this.txsEffectsHash), - ...to2Fields(this.inHash), - ...to2Fields(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`); @@ -50,9 +56,9 @@ export class ContentCommitment { const reader = FieldReader.asReader(fields); return new ContentCommitment( reader.readField(), - from2Fields(reader.readField(), reader.readField()), - from2Fields(reader.readField(), reader.readField()), - from2Fields(reader.readField(), reader.readField()), + fromTruncField(reader.readField()), + fromTruncField(reader.readField()), + fromTruncField(reader.readField()), ); } 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 3bbb90fa13e..438ea71f76f 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 @@ -118,8 +118,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(2, Fr), - reader.readArray(2, Fr), + reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readArray(NUM_FIELDS_PER_SHA256, Fr), Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), @@ -143,8 +143,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(2, Fr.zero), - makeTuple(2, Fr.zero), + makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), Fr.zero(), Fr.zero(), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), @@ -332,8 +332,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(2, Fr), - reader.readArray(2, Fr), + reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readArray(NUM_FIELDS_PER_SHA256, Fr), Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), @@ -371,8 +371,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(2, Fr.zero), - makeTuple(2, Fr.zero), + makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), Fr.zero(), Fr.zero(), makeTuple(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), @@ -458,8 +458,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(2, Fr), - reader.readArray(2, Fr), + reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readArray(NUM_FIELDS_PER_SHA256, Fr), Fr.fromBuffer(reader), Fr.fromBuffer(reader), ); @@ -481,8 +481,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(2, Fr.zero), - makeTuple(2, Fr.zero), + makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), Fr.zero(), Fr.zero(), ); diff --git a/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts b/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts index 7f70c6239ef..3edf7909091 100644 --- a/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/parity/parity_public_inputs.ts @@ -9,12 +9,12 @@ export class ParityPublicInputs { /** Aggregated proof of all the parity circuit iterations. */ public aggregationObject: AggregationObject, /** Root of the SHA256 tree. */ - public shaRoot: Buffer, + public shaRoot: Fr, /** Root of the converted tree. */ public convertedRoot: Fr, ) { - if (shaRoot.length !== 32) { - throw new Error(`shaRoot buffer must be 32 bytes. Got ${shaRoot.length} bytes`); + if (shaRoot.toBuffer()[0] != 0) { + throw new Error(`shaRoot buffer must be 31 bytes. Got 32 bytes`); } } @@ -32,6 +32,6 @@ export class ParityPublicInputs { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new ParityPublicInputs(reader.readObject(AggregationObject), reader.readBytes(32), reader.readObject(Fr)); + return new ParityPublicInputs(reader.readObject(AggregationObject), reader.readObject(Fr), reader.readObject(Fr)); } } 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 be0a164074a..df9f69807f2 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 @@ -96,7 +96,7 @@ export class PublicCircuitPublicInputs { * 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. */ - public unencryptedLogsHash: [Fr, Fr], + public unencryptedLogsHash: Tuple, /** * Length of the unencrypted log preimages emitted in this function call. */ @@ -145,7 +145,7 @@ export class PublicCircuitPublicInputs { makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message.empty), Fr.ZERO, Fr.ZERO, - makeTuple(2, Fr.zero), + makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), Fr.ZERO, Header.empty(), AztecAddress.ZERO, 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 2b3e70c718c..d44621ca084 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,5 +1,5 @@ import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; import { NUM_FIELDS_PER_SHA256 } from '../../constants.gen.js'; import { AggregationObject } from '../aggregation_object.js'; @@ -42,12 +42,12 @@ export class BaseOrMergeRollupPublicInputs { * 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. */ - public txsEffectsHash: [Fr, Fr], + public txsEffectsHash: Tuple, /** * SHA256 hashes of outhash. Used to make public inputs constant-sized (to then be unpacked on-chain). * Note: Length 2 for high and low. */ - public outHash: [Fr, Fr], + public outHash: Tuple, ) {} /** @@ -65,8 +65,8 @@ export class BaseOrMergeRollupPublicInputs { reader.readObject(ConstantRollupData), reader.readObject(PartialStateReference), reader.readObject(PartialStateReference), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr, Fr], - reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr, Fr], + reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr], + reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr], ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index ae3cf0853ff..056fc3d5133 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -289,8 +289,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(2, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(2, fr, seed + 0x800), // unencrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, 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 +311,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(2, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(2, fr, seed + 0x800), // unencrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, 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 +333,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(2, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(2, fr, seed + 0x800), // unencrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash + tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length ); @@ -427,7 +427,7 @@ export function makePublicCircuitPublicInputs( tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, makeL2ToL1Message, seed + 0x900), fr(seed + 0xa00), fr(seed + 0xa01), - tupleGenerator(2, fr, seed + 0x901), + tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x901), fr(seed + 0x902), makeHeader(seed + 0xa00, undefined), makeAztecAddress(seed + 0xb01), @@ -994,8 +994,8 @@ export function makeBaseOrMergeRollupPublicInputs( makeConstantBaseRollupData(seed + 0x200, globalVariables), makePartialStateReference(seed + 0x300), makePartialStateReference(seed + 0x400), - [fr(seed + 0x901), fr(seed + 0x902)], - [fr(seed + 0x903), fr(seed + 0x904)], + [fr(seed + 0x901)], + [fr(seed + 0x902)], ); } @@ -1043,7 +1043,7 @@ export function makeRootParityInput(seed = 0): RootParityInput { export function makeParityPublicInputs(seed = 0): ParityPublicInputs { return new ParityPublicInputs( makeAggregationObject(seed), - toBufferBE(BigInt(seed + 0x200), 32), + new Fr(BigInt(seed + 0x200)), new Fr(BigInt(seed + 0x300)), ); } 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 34ce2da58d0..5fb8ee541c8 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 @@ -11,7 +11,7 @@ import { computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { sha256 } from '@aztec/foundation/crypto'; -import { serializeToBuffer } from '@aztec/foundation/serialize'; +import { serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts.js'; import { toFunctionSelector } from 'viem/utils'; @@ -157,14 +157,14 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgLeaf); // 3. Consume L1 -> L2 message and mint private tokens on L2 - const content = Fr.fromBufferReduce( + const content = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount)]), ]), ), - ); + )[0]; const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -235,14 +235,14 @@ describe('e2e_cross_chain_messaging', () => { // Wait for the message to be available for consumption await crossChainTestHarness.makeMessageConsumable(msgLeaf); - const content = Fr.fromBufferReduce( + const content = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount)]), ]), ), - ); + )[0]; 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 dd63b6964f7..98f1f3e655e 100644 --- a/yarn-project/end-to-end/src/e2e_outbox.test.ts +++ b/yarn-project/end-to-end/src/e2e_outbox.test.ts @@ -8,6 +8,7 @@ import { SiblingPath, sha256, } from '@aztec/aztec.js'; +import { toTruncField, truncateAndPad } from '@aztec/foundation/serialize'; import { SHA256 } from '@aztec/merkle-tree'; import { TestContract } from '@aztec/noir-contracts.js'; @@ -92,13 +93,17 @@ describe('E2E Outbox Tests', () => { : [l2ToL1Message.toBuffer(), siblingPath.toBufferArray()[0]]; const firstLayer = merkleSha256.hash(...firstLayerInput); index /= 2; + // In the circuit, the 'firstLayer' is the kernel out hash, which is truncated to 31 bytes + // To match the result, the below preimages and the output are truncated to 31 then padded const secondLayerInput: [Buffer, Buffer] = - index & 0x1 ? [siblingPath.toBufferArray()[1], firstLayer] : [firstLayer, siblingPath.toBufferArray()[1]]; - return merkleSha256.hash(...secondLayerInput); + index & 0x1 + ? [siblingPath.toBufferArray()[1], truncateAndPad(firstLayer)] + : [truncateAndPad(firstLayer), siblingPath.toBufferArray()[1]]; + return truncateAndPad(merkleSha256.hash(...secondLayerInput)); } function makeL2ToL1Message(recipient: EthAddress, content: Fr = Fr.ZERO): Fr { - const leaf = Fr.fromBufferReduce( + const leaf = toTruncField( sha256( Buffer.concat([ contract.address.toBuffer(), @@ -108,7 +113,7 @@ describe('E2E Outbox Tests', () => { content.toBuffer(), ]), ), - ); + )[0]; return leaf; } diff --git a/yarn-project/end-to-end/src/e2e_p2p_network.test.ts b/yarn-project/end-to-end/src/e2e_p2p_network.test.ts index 5f8c8030176..618986c2ab1 100644 --- a/yarn-project/end-to-end/src/e2e_p2p_network.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p_network.test.ts @@ -130,7 +130,7 @@ describe('e2e_p2p_network', () => { error: '', }), ); - logger(`Receipt received and expecting contract deployment at ${origin}`); + logger(`Receipt received`); txs.push(tx); } return txs; 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 34bc3259b4b..d9561fee104 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 @@ -15,7 +15,7 @@ import { computeMessageSecretHash, } from '@aztec/aztec.js'; import { sha256 } from '@aztec/foundation/crypto'; -import { serializeToBuffer } from '@aztec/foundation/serialize'; +import { serializeToBuffer, toTruncField } 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'; @@ -150,14 +150,14 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgLeaf); - const content = Fr.fromBufferReduce( + const content = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount)]), ]), ), - ); + )[0]; const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -204,14 +204,14 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgLeaf); // Wrong message hash - const content = Fr.fromBufferReduce( + const content = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), serializeToBuffer(...[secretHash, new Fr(bridgeAmount)]), ]), ), - ); + )[0]; const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -258,7 +258,7 @@ describe('e2e_public_cross_chain_messaging', () => { content: content.toString() as Hex, }; - const leaf = Fr.fromBufferReduce( + const leaf = toTruncField( sha256( Buffer.concat([ testContract.address.toBuffer(), @@ -268,7 +268,7 @@ describe('e2e_public_cross_chain_messaging', () => { content.toBuffer(), ]), ), - ); + )[0]; const [l2MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( l2TxReceipt.blockNumber!, 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 f8f88fbf4ea..415d3aca702 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 @@ -1,15 +1,5 @@ import { getConfigEnvVars } from '@aztec/aztec-node'; -import { - AztecAddress, - Body, - Fr, - GlobalVariables, - L2Actor, - L2Block, - createDebugLogger, - mockTx, - to2Fields, -} from '@aztec/aztec.js'; +import { AztecAddress, Body, Fr, GlobalVariables, L2Actor, L2Block, createDebugLogger, mockTx } from '@aztec/aztec.js'; import { EthAddress, Header, @@ -26,9 +16,10 @@ 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 { SHA256, StandardTree } from '@aztec/merkle-tree'; +import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { EmptyRollupProver, L1Publisher, @@ -183,8 +174,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 = to2Fields(processedTx.encryptedLogs.hash()); - processedTx.data.end.unencryptedLogsHash = to2Fields(processedTx.unencryptedLogs.hash()); + processedTx.data.end.encryptedLogsHash = toTruncField(processedTx.encryptedLogs.hash()); + processedTx.data.end.unencryptedLogsHash = toTruncField(processedTx.unencryptedLogs.hash()); return processedTx; }; @@ -324,9 +315,9 @@ describe('L1Publisher integration', () => { data: txLog.data, topics: txLog.topics, }); - - // We check that the txsEffectsHash in the TxsPublished event is as expected - expect(topics.args.txsEffectsHash).toEqual(`0x${body.getTxsEffectsHash().toString('hex')}`); + // Sol gives bytes32 txsHash, so we pad the ts bytes31 version + // We check that the txsHash in the TxsPublished event is as expected + expect(topics.args.txsEffectsHash).toEqual(`0x${body.getTxsEffectsHash().toString('hex').padStart(64, '0')}`); }); it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => { @@ -416,7 +407,7 @@ describe('L1Publisher integration', () => { const treeHeight = Math.ceil(Math.log2(newL2ToL1MsgsArray.length)); - const tree = new StandardTree(openTmpStore(true), new SHA256(), 'temp_outhash_sibling_path', treeHeight); + const tree = new StandardTree(openTmpStore(true), new SHA256Trunc(), 'temp_outhash_sibling_path', treeHeight); await tree.appendLeaves(newL2ToL1MsgsArray.map(l2ToL1Msg => l2ToL1Msg.toBuffer())); const expectedRoot = tree.getRoot(true); 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 12234db4b09..0453e64f68b 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 @@ -18,6 +18,7 @@ import { retryUntil, sha256, } from '@aztec/aztec.js'; +import { toTruncField } from '@aztec/foundation/serialize'; import { InboxAbi, OutboxAbi, @@ -363,7 +364,7 @@ export class CrossChainTestHarness { } getL2ToL1MessageLeaf(withdrawAmount: bigint, callerOnL1: EthAddress = EthAddress.ZERO): Fr { - const content = Fr.fromBufferReduce( + const content = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), @@ -372,8 +373,8 @@ export class CrossChainTestHarness { callerOnL1.toBuffer32(), ]), ), - ); - const leaf = Fr.fromBufferReduce( + )[0]; + const leaf = toTruncField( sha256( Buffer.concat([ this.l2Bridge.address.toBuffer(), @@ -383,7 +384,7 @@ export class CrossChainTestHarness { content.toBuffer(), ]), ), - ); + )[0]; 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 41727806769..dd60e379ea6 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 @@ -10,6 +10,7 @@ import { } from '@aztec/aztec.js'; import { deployL1Contract } from '@aztec/ethereum'; import { sha256 } from '@aztec/foundation/crypto'; +import { toTruncField } from '@aztec/foundation/serialize'; import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap'; @@ -246,7 +247,7 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPrivateContent = Fr.fromBufferReduce( + const swapPrivateContent = toTruncField( sha256( Buffer.concat([ Buffer.from( @@ -265,9 +266,9 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress.toBuffer32(), ]), ), - ); + )[0]; - const swapPrivateLeaf = Fr.fromBufferReduce( + const swapPrivateLeaf = toTruncField( sha256( Buffer.concat([ uniswapL2Contract.address.toBuffer(), @@ -277,9 +278,9 @@ export const uniswapL1L2TestSuite = ( swapPrivateContent.toBuffer(), ]), ), - ); + )[0]; - const withdrawContent = Fr.fromBufferReduce( + const withdrawContent = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), @@ -288,9 +289,9 @@ export const uniswapL1L2TestSuite = ( uniswapPortalAddress.toBuffer32(), ]), ), - ); + )[0]; - const withdrawLeaf = Fr.fromBufferReduce( + const withdrawLeaf = toTruncField( sha256( Buffer.concat([ wethCrossChainHarness.l2Bridge.address.toBuffer(), @@ -300,7 +301,7 @@ export const uniswapL1L2TestSuite = ( withdrawContent.toBuffer(), ]), ), - ); + )[0]; // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -475,7 +476,7 @@ export const uniswapL1L2TestSuite = ( // 4.2 Call swap_public from user2 on behalf of owner const uniswapL2Interaction = await action.send().wait(); - const swapPublicContent = Fr.fromBufferReduce( + const swapPublicContent = toTruncField( sha256( Buffer.concat([ Buffer.from( @@ -494,9 +495,9 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress.toBuffer32(), ]), ), - ); + )[0]; - const swapPublicLeaf = Fr.fromBufferReduce( + const swapPublicLeaf = toTruncField( sha256( Buffer.concat([ uniswapL2Contract.address.toBuffer(), @@ -506,9 +507,9 @@ export const uniswapL1L2TestSuite = ( swapPublicContent.toBuffer(), ]), ), - ); + )[0]; - const withdrawContent = Fr.fromBufferReduce( + const withdrawContent = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), @@ -517,9 +518,9 @@ export const uniswapL1L2TestSuite = ( uniswapPortalAddress.toBuffer32(), ]), ), - ); + )[0]; - const withdrawLeaf = Fr.fromBufferReduce( + const withdrawLeaf = toTruncField( sha256( Buffer.concat([ wethCrossChainHarness.l2Bridge.address.toBuffer(), @@ -529,7 +530,7 @@ export const uniswapL1L2TestSuite = ( withdrawContent.toBuffer(), ]), ), - ); + )[0]; // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -842,7 +843,7 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPrivateContent = Fr.fromBufferReduce( + const swapPrivateContent = toTruncField( sha256( Buffer.concat([ Buffer.from( @@ -861,9 +862,9 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress.toBuffer32(), ]), ), - ); + )[0]; - const swapPrivateLeaf = Fr.fromBufferReduce( + const swapPrivateLeaf = toTruncField( sha256( Buffer.concat([ uniswapL2Contract.address.toBuffer(), @@ -873,9 +874,9 @@ export const uniswapL1L2TestSuite = ( swapPrivateContent.toBuffer(), ]), ), - ); + )[0]; - const withdrawContent = Fr.fromBufferReduce( + const withdrawContent = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), @@ -884,9 +885,9 @@ export const uniswapL1L2TestSuite = ( uniswapPortalAddress.toBuffer32(), ]), ), - ); + )[0]; - const withdrawLeaf = Fr.fromBufferReduce( + const withdrawLeaf = toTruncField( sha256( Buffer.concat([ wethCrossChainHarness.l2Bridge.address.toBuffer(), @@ -896,7 +897,7 @@ export const uniswapL1L2TestSuite = ( withdrawContent.toBuffer(), ]), ), - ); + )[0]; const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( withdrawReceipt.blockNumber!, @@ -979,7 +980,7 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPublicContent = Fr.fromBufferReduce( + const swapPublicContent = toTruncField( sha256( Buffer.concat([ Buffer.from( @@ -998,9 +999,9 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress.toBuffer32(), ]), ), - ); + )[0]; - const swapPublicLeaf = Fr.fromBufferReduce( + const swapPublicLeaf = toTruncField( sha256( Buffer.concat([ uniswapL2Contract.address.toBuffer(), @@ -1010,9 +1011,9 @@ export const uniswapL1L2TestSuite = ( swapPublicContent.toBuffer(), ]), ), - ); + )[0]; - const withdrawContent = Fr.fromBufferReduce( + const withdrawContent = toTruncField( sha256( Buffer.concat([ Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), @@ -1021,9 +1022,9 @@ export const uniswapL1L2TestSuite = ( uniswapPortalAddress.toBuffer32(), ]), ), - ); + )[0]; - const withdrawLeaf = Fr.fromBufferReduce( + const withdrawLeaf = toTruncField( sha256( Buffer.concat([ wethCrossChainHarness.l2Bridge.address.toBuffer(), @@ -1033,7 +1034,7 @@ export const uniswapL1L2TestSuite = ( withdrawContent.toBuffer(), ]), ), - ); + )[0]; const [swapPublicL2MessageIndex, swapPublicSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( withdrawReceipt.blockNumber!, diff --git a/yarn-project/foundation/src/serialize/free_funcs.test.ts b/yarn-project/foundation/src/serialize/free_funcs.test.ts index e3be26dd2d8..1f6133683e4 100644 --- a/yarn-project/foundation/src/serialize/free_funcs.test.ts +++ b/yarn-project/foundation/src/serialize/free_funcs.test.ts @@ -1,8 +1,8 @@ import { randomBytes } from '../crypto/index.js'; -import { from2Fields, to2Fields } from './free_funcs.js'; +import { from2Fields, fromTruncField, to2Fields, toTruncField } from './free_funcs.js'; describe('buffer to fields and back', () => { - it('should correctly serialize and deserialize a buffer', () => { + it('should correctly serialize and deserialize a buffer to two fields', () => { // Generate a random 32-byte buffer const originalBuffer = randomBytes(32); @@ -15,4 +15,18 @@ describe('buffer to fields and back', () => { // Check if the original buffer and reconstructed buffer are identical expect(reconstructedBuffer).toEqual(originalBuffer); }); + + it('should correctly serialize and deserialize a buffer to one truncated field', () => { + // Generate a random 31-byte buffer padded to 32 + const originalBuffer = Buffer.concat([Buffer.alloc(1), randomBytes(31)]); + + // Serialize the buffer to one field + const field = toTruncField(originalBuffer)[0]; + + // Deserialize the field back to a buffer + const reconstructedBuffer = fromTruncField(field); + + // Check if the original buffer and reconstructed buffer are identical + expect(reconstructedBuffer).toEqual(originalBuffer); + }); }); diff --git a/yarn-project/foundation/src/serialize/free_funcs.ts b/yarn-project/foundation/src/serialize/free_funcs.ts index 5c7aa27e48e..17260de202e 100644 --- a/yarn-project/foundation/src/serialize/free_funcs.ts +++ b/yarn-project/foundation/src/serialize/free_funcs.ts @@ -147,6 +147,48 @@ export function from2Fields(field1: Fr, field2: Fr): Buffer { return Buffer.concat([originalPart1, originalPart2]); } +/** + * Truncates SHA hashes to match Noir's truncated version + * @param buf - 32 bytes of data + * @returns 31 bytes of data padded to 32 + */ +export function truncateAndPad(buf: Buffer): Buffer { + // Note that we always truncate here, to match solidity's sha256ToField() + if (buf.length !== 32) { + throw new Error('Buffer to truncate must be 32 bytes'); + } + return Buffer.concat([Buffer.alloc(1), buf.subarray(0, 31)]); +} + +/** + * Stores 248 bits of information in 1 field. + * @param buf - 32 or 31 bytes of data + * @returns 1 field element + */ +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)]; + } else { + return [Fr.fromBuffer(buf.subarray(0, 31))]; + } +} + +/** + * Reconstructs the original 31 bytes of data from 1 truncated field element. + * @param field - field element + * @returns 31 bytes of data as a Buffer + */ +export function fromTruncField(field: Fr): Buffer { + const buffer = field.toBuffer(); + if (buffer[0] != 0) { + throw new Error(`Number ${field} does not fit in 31 byte truncated buffer`); + } + return buffer; +} + export function fromFieldsTuple(fields: Tuple): Buffer { return from2Fields(fields[0], fields[1]); } diff --git a/yarn-project/merkle-tree/src/sha_256.ts b/yarn-project/merkle-tree/src/sha_256.ts index 2ed2ba5a35d..2945e0705d0 100644 --- a/yarn-project/merkle-tree/src/sha_256.ts +++ b/yarn-project/merkle-tree/src/sha_256.ts @@ -1,4 +1,5 @@ import { sha256 } from '@aztec/foundation/crypto'; +import { truncateAndPad } from '@aztec/foundation/serialize'; import { Hasher } from '@aztec/types/interfaces'; /** @@ -23,3 +24,26 @@ export class SHA256 implements Hasher { return sha256(Buffer.concat(inputs)); } } + +/** + * A helper class encapsulating truncated SHA256 hash functionality. + * @deprecated Don't call SHA256 directly in production code. Instead, create suitably-named functions for specific + * purposes. + */ +export class SHA256Trunc implements Hasher { + /* + * @deprecated Don't call SHA256 directly in production code. Instead, create suitably-named functions for specific + * purposes. + */ + public hash(lhs: Uint8Array, rhs: Uint8Array): Buffer { + return truncateAndPad(sha256(Buffer.concat([Buffer.from(lhs), Buffer.from(rhs)]))); + } + + /* + * @deprecated Don't call SHA256 directly in production code. Instead, create suitably-named functions for specific + * purposes. + */ + public hashInputs(inputs: Buffer[]): Buffer { + return truncateAndPad(sha256(Buffer.concat(inputs))); + } +} 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 56f92fda871..f9463a7ba89 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 @@ -35,22 +35,22 @@ PrivateKernelInnerCircuitPublicInputs { "constants": CombinedConstantData { "historicalHeader": Header { "contentCommitment": ContentCommitment { - "inHash": Buffer<0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c>, - "outHash": Buffer<0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71>, + "inHash": Buffer<0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c>, + "outHash": Buffer<0x0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c3>, "txTreeHeight": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "txsEffectsHash": Buffer<0x9acc81dd5daac41a17c147883858c2ddde37dfa685f0ec87cc9d24b378ca7af1>, + "txsEffectsHash": Buffer<0x002807c70858235323a27419dde0fc745fbab002f33c34d1dc41994b43d27d5e>, }, "globalVariables": { "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065facfd9", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065fc0c66", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, - "root": Fr<0x10bce690e1edd4b74c89f0871fc3cf69c774c3b5a7034d3780b25a62ac55fe20>, + "root": Fr<0x2d799018a5143b5406d2f66ff03e3e026396ea094ad3775bffc2e63f71c7ef4f>, }, "state": StateReference { "l1ToL2MessageTree": AppendOnlyTreeSnapshot { @@ -60,11 +60,11 @@ PrivateKernelInnerCircuitPublicInputs { "partial": PartialStateReference { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, - "root": Fr<0x06dc88979aca45877629fb66385e708804b2e2b73e93ecdf1c5b60608e50b533>, + "root": Fr<0x198bc624121dc20ca9346776cefe5816f1c745b71d7c78bcd66c165ab2fd93cc>, }, "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, - "root": Fr<0x058b36fce700c0b7ce1512c8311a821a818ab9e1e816e08216eef47522081710>, + "root": Fr<0x1ede270b6a66d2c49eafb1dc2815aff988a10ab9d96cabc4a89d59e5b8259406>, }, "publicDataTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 256, @@ -83,8 +83,7 @@ PrivateKernelInnerCircuitPublicInputs { "end": CombinedAccumulatedData { "encryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, "encryptedLogsHash": [ - Fr<0x000000000000000000000000000000000803f3447b3110b5579626c7861d0793>, - Fr<0x00000000000000000000000000000000645004856e6d7946b8eb30aa1c098a2c>, + Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -352,7 +351,7 @@ PrivateKernelInnerCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1891e2e028579e5ad63ccd2eb7c913758b9f6942082ab32c67b50237e5903f73>, + "value": Fr<0x0a5523db965e4ceccdfdfd2e03ca00371c99d4e44eab1c1a9961089f04eaf648>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1001,8 +1000,7 @@ PrivateKernelInnerCircuitPublicInputs { }, "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, "unencryptedLogsHash": [ - Fr<0x000000000000000000000000000000000803f3447b3110b5579626c7861d0793>, - Fr<0x00000000000000000000000000000000645004856e6d7946b8eb30aa1c098a2c>, + Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, ], }, "isPrivate": true, @@ -1893,8 +1891,7 @@ PrivateKernelTailCircuitPublicInputs { "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, "encryptedLogsHash": [ - Fr<0x00000000000000000000000000000000b357911acc1e83efb776844a2de3e979>, - Fr<0x000000000000000000000000000000001a1d29d9ab6f39509074e3374976637b>, + Fr<0x000a6f11d0fee649628137ebedf70c9cf2e7b081a9e284c9608fc5741fa8fc7a>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1903,7 +1900,7 @@ PrivateKernelTailCircuitPublicInputs { "newNoteHashes": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, - "value": Fr<0x0ff4f5c03e850220118d86825842940a55f68fd9408d5963c8b57117eee6418a>, + "value": Fr<0x0f09b243c65692d3eeebc1521a64db5de9d9cf48fb8aa213693bf7989b195210>, }, SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2130,12 +2127,12 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1434977d46c496efafb397806f96c1d348088add5f82a2334ff1c621b6ee82da>, + "value": Fr<0x00e39690b5006763b3b7c0929ee4deb8fbe7cb9fc5aa86a270e4b7a90be7d254>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000003>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x27f45cb4f2ecb63d53782f0f47ead3754f28e6d81fa6cc7c02bbee317414ab0e>, + "value": Fr<0x1cd3c5ccb8644ae3a8cbfad44981cabd453de0e0648de28ff014c67ddcdd885d>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2544,8 +2541,7 @@ PrivateKernelTailCircuitPublicInputs { ], "unencryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000004>, "unencryptedLogsHash": [ - Fr<0x000000000000000000000000000000001c9ecec90e28d2461650418635878a5c>, - Fr<0x0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e897112>, + Fr<0x006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b39>, ], }, "endNonRevertibleData": PrivateAccumulatedNonRevertibleData { @@ -2587,7 +2583,7 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x155c9f14afe2c1a016416e20b6eb48fc1a69fd845b22d25d87a4037a5c602af4>, + "value": Fr<0x232f8201f6ff6b414f9b54af28b9a33cbe45817a0f7fe0cd1e8712e86158c2c3>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, diff --git a/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-init.hex b/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-init.hex index 59061faf4b2..0e4647f2331 100644 --- a/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-init.hex +++ b/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-init.hex @@ -1 +1 @@ -0942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c8945af9f8c44011c20592cef765eb752a13425f604a209f0ed694aff35ed85d9eb00e83a250ca400000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c8945af9f8c440100000000000000000000000000000000000000000000000000000000000000000942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c89450000000000000000000000000000000000000000af9f8c440000000000011c20592cef765eb752a13425f604a209f0ed694aff35ed85d9eb00e83a250ca4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e15a4714ddf8d2baa6528b94e6e9a66b7a76f656feb3a6455e26ff1a18b95000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c89450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000003c2b53bcf58b2e5904071541672570b70000000000000000000000000000000028ff47704a5f2798c61b8ccec269605100000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b6066c969c7bcbca004fc8c86e17bf9bc3a3c3134f3b86e105b7616ff4592c306b00b2b88cb098d36d1c49ab1fcfb6bac7b80b3caf557c9869741e6d9c5d595c6d10e22f09a1e17e8ce9c4895071e6a2fa3a699a8b6dc7b5a978ba1a87b78adb7f00000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f71af9f8c4401265e8b9ed5e467516840b4a93738d252ae67b8db649df98647d23e734f0134d700000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f71af9f8c44010000000000000000000000000000000000000000000000000000000000000000012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f710000000000000000000000000000000000000000af9f8c44000000000001265e8b9ed5e467516840b4a93738d252ae67b8db649df98647d23e734f0134d700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e9300a54e4ef726427ca380a004f96311ad780f5d2dacafa8f7a97a179a2d1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004009bb0a86ebb01636865332b3ab8c3c46ae6d2148c59ce3d431798b0926d7cea00e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b80000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b60f631bbbc88cff6a2075e290bb401efac78614b1948d7fcf2ee95eced96e56f01ff429915e11f4fef0121ffa71c37c46f5ab5be8a7fcb1c75e1be272b1d7c4e51a0c48a4ca89d949e9cf26eb9d19f7c019d49f006c5d813b23ee8821885f287500000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-inner.hex b/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-inner.hex index 7c69ca6ec75..89aa6b4b975 100644 --- a/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-inner.hex +++ b/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-inner.hex @@ -1 +1 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001891e2e028579e5ad63ccd2eb7c913758b9f6942082ab32c67b50237e5903f73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e27a1c5702bf7a522fa82d3600f6152e33964fde527439fdcbf9465914172ea25ffcd069cb9117564a0de20ffaba3b44877cb7530fb66411fc7f374e46618cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010bce690e1edd4b74c89f0871fc3cf69c774c3b5a7034d3780b25a62ac55fe200000000300000000000000000000000000000000000000000000000000000000000000019acc81dd5daac41a17c147883858c2ddde37dfa685f0ec87cc9d24b378ca7af1536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003006dc88979aca45877629fb66385e708804b2e2b73e93ecdf1c5b60608e50b53300000180058b36fce700c0b7ce1512c8311a821a818ab9e1e816e08216eef47522081710000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facfd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002b02c534c7b92bf4fe2d46dc09d7b7ba5350291fa5fe7903540564fff86e605315bc9e9af48e296f9ed13484d6053e16b6a9c7f9236ef72f541a237de37233f418751db8b68e7cccf7c506420dffe35516b0d1e21bf0db802f87dbc5f7b20ccd05c0b8bd2ad8f4236d0c610e5113b2ba74d382ae33d32c194d6ee577c07e98a70906bca10125ffcd069cb9117564a0de20ffaba3b44877cb7530fb66411fc7f374e46618cd05c0b8bd2ad8f4236d0c610e5113b2ba74d382ae33d32c194d6ee577c07e98a700000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000410bce690e1edd4b74c89f0871fc3cf69c774c3b5a7034d3780b25a62ac55fe200000000300000000000000000000000000000000000000000000000000000000000000019acc81dd5daac41a17c147883858c2ddde37dfa685f0ec87cc9d24b378ca7af1536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003006dc88979aca45877629fb66385e708804b2e2b73e93ecdf1c5b60608e50b53300000180058b36fce700c0b7ce1512c8311a821a818ab9e1e816e08216eef47522081710000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facfd9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f52bf6d6b819de915557c405100f0213a18e97f71d170d54b168ac69922bc7c5c027b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed18bb09f0d69419d2f6e793576065e305a019fcb1202c844158d9903fbfe2803100000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a5523db965e4ceccdfdfd2e03ca00371c99d4e44eab1c1a9961089f04eaf6480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015a4077e390d955b1eaadd6fce2e68dc52fdf6b61869605782f89b8b319a610919d5714848f14aaee158c89b919018fe14df4da0bf053e76572749e7c79fde9a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d4d695766a616808caa331119da14269ac3271c251dec3a11df896131ba2c008d4d695766a616808caa331119da14269ac3271c251dec3a11df896131ba2c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d799018a5143b5406d2f66ff03e3e026396ea094ad3775bffc2e63f71c7ef4f000000030000000000000000000000000000000000000000000000000000000000000001002807c70858235323a27419dde0fc745fbab002f33c34d1dc41994b43d27d5e00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030198bc624121dc20ca9346776cefe5816f1c745b71d7c78bcd66c165ab2fd93cc000001801ede270b6a66d2c49eafb1dc2815aff988a10ab9d96cabc4a89d59e5b8259406000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065fc0c660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000001e5533f995951f79050807511750359988348e7cb8a6d4feca2e56be08f7201b05f0e778ca470d8ea971daa525ad9654df5fa38aeb886b7f81baf1d6a63e35561e5f0937571725d7cd5a9d9b16d6e84bb9241002d843c07115f97ccd81778c8b1a877bd4951d7481a0f5d368f986b10cdbd1db091b07605e7b966cc2acf0edc80906bca10119d5714848f14aaee158c89b919018fe14df4da0bf053e76572749e7c79fde9a1a877bd4951d7481a0f5d368f986b10cdbd1db091b07605e7b966cc2acf0edc800000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b800e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000042d799018a5143b5406d2f66ff03e3e026396ea094ad3775bffc2e63f71c7ef4f000000030000000000000000000000000000000000000000000000000000000000000001002807c70858235323a27419dde0fc745fbab002f33c34d1dc41994b43d27d5e00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030198bc624121dc20ca9346776cefe5816f1c745b71d7c78bcd66c165ab2fd93cc000001801ede270b6a66d2c49eafb1dc2815aff988a10ab9d96cabc4a89d59e5b8259406000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065fc0c66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f507c4047932d001dc63b0e8e7471fc6d2085380441776c1346c4d7a978112de0827b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed0299c25a4d23dbcf5f0968157e4c0a1cc47900a648874b61c852a22282121b2f00000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-ordering.hex b/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-ordering.hex index e5a9d73a0d3..9a9e4c25b9e 100644 --- a/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-ordering.hex +++ b/yarn-project/noir-protocol-circuits-types/src/fixtures/nested-call-private-kernel-ordering.hex @@ -1 +1 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eb15335f7c5e52e0a969e163f706c19da24592ccb6b682c8d66de0abb0471450000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000155c9f14afe2c1a016416e20b6eb48fc1a69fd845b22d25d87a4037a5c602af4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001434977d46c496efafb397806f96c1d348088add5f82a2334ff1c621b6ee82da0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000127f45cb4f2ecb63d53782f0f47ead3754f28e6d81fa6cc7c02bbee317414ab0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b357911acc1e83efb776844a2de3e979000000000000000000000000000000001a1d29d9ab6f39509074e3374976637b000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000026f5f89e45ded841cfc7ec410402b6d70ecff7e8fa1e157393ac9a9c4e3534312d68331d0cad83efbed489288d93088de8e232c4ee605cc4856347ca9ed193b722c04e8eecc88ebc60127ece1554a2156da87ceb4f5c67d61785b53686dfa0950eb15335f7c5e52e0a969e163f706c19da24592ccb6b682c8d66de0abb0471450000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000155c9f14afe2c1a016416e20b6eb48fc1a69fd845b22d25d87a4037a5c602af4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001434977d46c496efafb397806f96c1d348088add5f82a2334ff1c621b6ee82da0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000127f45cb4f2ecb63d53782f0f47ead3754f28e6d81fa6cc7c02bbee317414ab0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000178208c093e3944e4f2b13d0bf421b3a3910e2c86af2f2fc45b304457839dcf10000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232f8201f6ff6b414f9b54af28b9a33cbe45817a0f7fe0cd1e8712e86158c2c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e39690b5006763b3b7c0929ee4deb8fbe7cb9fc5aa86a270e4b7a90be7d254000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011cd3c5ccb8644ae3a8cbfad44981cabd453de0e0648de28ff014c67ddcdd885d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a6f11d0fee649628137ebedf70c9cf2e7b081a9e284c9608fc5741fa8fc7a006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b3900000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000022e7b215f6cd58e2d7ad5641f7b39178f03c673b5018bed2fd2d2ffb4b3658b52530d38b1644323d271542478281cfd55e816d6ae19f2f0da539762e0494b6fe2f1b66a8ced84b80de4e4129c44f7f7e68e91d75a55db7dd2ae34f93c010ac77178208c093e3944e4f2b13d0bf421b3a3910e2c86af2f2fc45b304457839dcf10000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232f8201f6ff6b414f9b54af28b9a33cbe45817a0f7fe0cd1e8712e86158c2c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e39690b5006763b3b7c0929ee4deb8fbe7cb9fc5aa86a270e4b7a90be7d254000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011cd3c5ccb8644ae3a8cbfad44981cabd453de0e0648de28ff014c67ddcdd885d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file 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 5baadb76543..daac082af2b 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -47,6 +47,7 @@ import { MembershipWitness, MergeRollupInputs, NULLIFIER_TREE_HEIGHT, + NUM_BYTES_PER_SHA256, NUM_FIELDS_PER_SHA256, NonMembershipHint, NoteHashReadRequestMembershipWitness, @@ -104,7 +105,8 @@ import { TxRequest, ValidationRequests, } from '@aztec/circuits.js'; -import { Tuple, from2Fields, mapTuple, to2Fields } from '@aztec/foundation/serialize'; +import { toBufferBE } from '@aztec/foundation/bigint-buffer'; +import { Tuple, mapTuple, toTruncField } from '@aztec/foundation/serialize'; import { BaseParityInputs as BaseParityInputsNoir } from './types/parity_base_types.js'; import { RootParityInputs as RootParityInputsNoir } from './types/parity_root_types.js'; @@ -805,20 +807,20 @@ export function mapTupleFromNoir( /** * Maps a SHA256 hash from noir to the parsed type. - * @param hash - The hash as it is represented in Noir (2 fields). - * @returns The hash represented as a 32 bytes long buffer. + * @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 from2Fields(mapFieldFromNoir(hash[0]), mapFieldFromNoir(hash[1])); +export function mapSha256HashFromNoir(hash: FixedLengthArray): Buffer { + return Buffer.concat(hash.map(mapFieldFromNoir).map(fr => toBufferBE(fr.toBigInt(), NUM_BYTES_PER_SHA256))); } /** * Maps a sha256 to the representation used in noir. * @param hash - The hash represented as a 32 bytes long buffer. - * @returns The hash as it is represented in Noir (2 fields). + * @returns The hash as it is represented in Noir (1 field, truncated). */ -export function mapSha256HashToNoir(hash: Buffer): FixedLengthArray { - return to2Fields(hash).map(mapFieldToNoir) as FixedLengthArray; +export function mapSha256HashToNoir(hash: Buffer): FixedLengthArray { + return toTruncField(hash).map(mapFieldToNoir) as FixedLengthArray; } /** @@ -1615,8 +1617,8 @@ export function mapBaseOrMergeRollupPublicInputsFromNoir( mapConstantRollupDataFromNoir(baseOrMergeRollupPublicInputs.constants), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.start), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.end), - mapTupleFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash, 2, mapFieldFromNoir), - mapTupleFromNoir(baseOrMergeRollupPublicInputs.out_hash, 2, mapFieldFromNoir), + mapTupleFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapTupleFromNoir(baseOrMergeRollupPublicInputs.out_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), ); } @@ -1696,7 +1698,7 @@ export function mapRootParityInputToNoir(rootParityInput: RootParityInput): Root export function mapParityPublicInputsToNoir(parityPublicInputs: ParityPublicInputs): ParityPublicInputsNoir { return { aggregation_object: {}, - sha_root: mapSha256HashToNoir(parityPublicInputs.shaRoot), + sha_root: mapFieldToNoir(parityPublicInputs.shaRoot), converted_root: mapFieldToNoir(parityPublicInputs.convertedRoot), }; } @@ -1724,7 +1726,7 @@ export function mapRootRollupPublicInputsFromNoir( export function mapParityPublicInputsFromNoir(parityPublicInputs: ParityPublicInputsNoir): ParityPublicInputs { return new ParityPublicInputs( AggregationObject.makeFake(), - mapSha256HashFromNoir(parityPublicInputs.sha_root), + mapFieldFromNoir(parityPublicInputs.sha_root), mapFieldFromNoir(parityPublicInputs.converted_root), ); } diff --git a/yarn-project/scripts/package.local.json b/yarn-project/scripts/package.local.json index 05cdf4290ec..b9d7870a0fc 100644 --- a/yarn-project/scripts/package.local.json +++ b/yarn-project/scripts/package.local.json @@ -6,4 +6,4 @@ "generate:why-these-noops": "echo These noops are here because `yarn workspaces foreach` runs the specified command in the packages that contain it only if two or more packages define it, otherwise it's run everywhere. So we just define these noops as commands to ensure they behave as they should when running watch.sh.", "generate:why-these-comments": "echo JSON does not support comments, so we just define these commands for documentation sake." } -} \ No newline at end of file +} diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index f650be07ffa..568dc8e56dc 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -45,7 +45,7 @@ import { import { makeTuple, range } from '@aztec/foundation/array'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { padArrayEnd, times } from '@aztec/foundation/collection'; -import { to2Fields } from '@aztec/foundation/serialize'; +import { toTruncField } from '@aztec/foundation/serialize'; import { openTmpStore } from '@aztec/kv-store/utils'; import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; @@ -227,12 +227,12 @@ describe('sequencer/solo_block_builder', () => { // Calculate what would be the tree roots after the first tx and update mock circuit output await updateExpectedTreesFromTxs([txs[0]]); baseRollupOutputLeft.end = await getPartialStateReference(); - baseRollupOutputLeft.txsEffectsHash = to2Fields(toTxEffect(tx).hash()); + baseRollupOutputLeft.txsEffectsHash = toTruncField(toTxEffect(tx).hash()); // Same for the tx on the right await updateExpectedTreesFromTxs([txs[1]]); baseRollupOutputRight.end = await getPartialStateReference(); - baseRollupOutputRight.txsEffectsHash = to2Fields(toTxEffect(tx).hash()); + baseRollupOutputRight.txsEffectsHash = toTruncField(toTxEffect(tx).hash()); // Update l1 to l2 message tree await updateL1ToL2MessageTree(mockL1ToL2Messages); @@ -347,8 +347,8 @@ describe('sequencer/solo_block_builder', () => { 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 = to2Fields(processedTx.encryptedLogs.hash()); - processedTx.data.end.unencryptedLogsHash = to2Fields(processedTx.unencryptedLogs.hash()); + processedTx.data.end.encryptedLogsHash = toTruncField(processedTx.encryptedLogs.hash()); + processedTx.data.end.unencryptedLogsHash = toTruncField(processedTx.unencryptedLogs.hash()); return processedTx; }; diff --git a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts index 700e2250e63..f703a22af69 100644 --- a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts +++ b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts @@ -77,7 +77,7 @@ export class ViemTxSender implements L1PublisherTxSender { } checkIfTxsAreAvailable(block: L2Block): Promise { - const args = [`0x${block.body.getTxsEffectsHash().toString('hex')}`] as const; + const args = [`0x${block.body.getTxsEffectsHash().toString('hex').padStart(64, '0')}`] as const; return this.availabilityOracleContract.read.isAvailable(args); } 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 8976c511ab6..8d143ed4f0a 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -42,7 +42,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, to2Fields } from '@aztec/foundation/serialize'; +import { Tuple, toTruncField } from '@aztec/foundation/serialize'; import { PublicExecution, PublicExecutionResult, @@ -349,7 +349,7 @@ export abstract class AbstractPhaseManager { ); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir - const unencryptedLogsHash = to2Fields(result.unencryptedLogs.hash()); + const unencryptedLogsHash = toTruncField(result.unencryptedLogs.hash()); const unencryptedLogPreimagesLength = new Fr(result.unencryptedLogs.getSerializedLength()); return PublicCircuitPublicInputs.from({ diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index 9b534720f5c..d8368e27370 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -14,7 +14,7 @@ import { ValidationRequests, makeEmptyProof, } from '@aztec/circuits.js'; -import { Tuple, fromFieldsTuple } from '@aztec/foundation/serialize'; +import { Tuple, toTruncField } from '@aztec/foundation/serialize'; /** * Represents a tx that has been processed by the sequencer public processor, @@ -192,12 +192,11 @@ export function toTxEffect(tx: ProcessedTx): TxEffect { function validateProcessedTxLogs(tx: ProcessedTx): void { const unencryptedLogs = tx.unencryptedLogs || new TxL2Logs([]); - const kernelUnencryptedLogsHash = fromFieldsTuple(tx.data.combinedData.unencryptedLogsHash); - if (!unencryptedLogs.hash().equals(kernelUnencryptedLogsHash)) { + const kernelUnencryptedLogsHash = tx.data.combinedData.unencryptedLogsHash[0]; + const referenceHash = toTruncField(unencryptedLogs.hash())[0]; + if (!referenceHash.equals(kernelUnencryptedLogsHash)) { throw new Error( - `Unencrypted logs hash mismatch. Expected ${unencryptedLogs - .hash() - .toString('hex')}, got ${kernelUnencryptedLogsHash.toString('hex')}. + `Unencrypted logs hash mismatch. Expected ${referenceHash.toString()}, got ${kernelUnencryptedLogsHash.toString()}. Processed: ${JSON.stringify(unencryptedLogs.toJSON())} Kernel Length: ${tx.data.combinedData.unencryptedLogPreimagesLength}`, ); 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 b0d55f688ec..126237a3f72 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -105,7 +105,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, Fr.ZERO]; + tx.data.end.unencryptedLogsHash = [Fr.ZERO]; tx.data.endNonRevertibleData.publicCallStack = makeTuple( MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, @@ -210,7 +210,7 @@ describe('public_processor', () => { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, ); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; const tx = new Tx(kernelOutput, proof, TxL2Logs.empty(), TxL2Logs.empty(), publicCallRequests); @@ -253,7 +253,7 @@ describe('public_processor', () => { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, ); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; kernelOutput.needsSetup = false; kernelOutput.needsTeardown = false; @@ -297,7 +297,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -413,7 +413,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -517,7 +517,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -621,7 +621,7 @@ describe('public_processor', () => { const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, 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 1abdd7136f6..1491b7d7dcb 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -3,7 +3,7 @@ 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 { to2Fields } from '@aztec/foundation/serialize'; +import { toTruncField } from '@aztec/foundation/serialize'; import { extractReturnWitness } from '../acvm/deserialize.js'; import { Oracle, acvm, extractCallStack } from '../acvm/index.js'; @@ -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 = to2Fields(encryptedLogs.hash()); + publicInputs.encryptedLogsHash = toTruncField(encryptedLogs.hash()); publicInputs.encryptedLogPreimagesLength = new Fr(encryptedLogs.getSerializedLength()); - publicInputs.unencryptedLogsHash = to2Fields(unencryptedLogs.hash()); + publicInputs.unencryptedLogsHash = toTruncField(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 c9f40a83af6..081e4320a53 100644 --- a/yarn-project/simulator/src/test/utils.ts +++ b/yarn-project/simulator/src/test/utils.ts @@ -2,6 +2,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'; /** * Test utility function to craft an L1 to L2 message. @@ -21,8 +22,7 @@ export const buildL1ToL2Message = ( const selectorBuf = Buffer.from(selector, 'hex'); const contentBuf = Buffer.concat([selectorBuf, ...contentPreimage.map(field => field.toBuffer())]); - const content = Fr.fromBufferReduce(sha256(contentBuf)); - + const content = toTruncField(sha256(contentBuf))[0]; const secretHash = computeMessageSecretHash(secret); // Eventually the kernel will need to prove the kernel portal pair exists within the contract tree, diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts index 8509109e0dd..d1c716adc30 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts @@ -6,7 +6,7 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { sleep } from '@aztec/foundation/sleep'; import { AztecKVStore } from '@aztec/kv-store'; import { openTmpStore } from '@aztec/kv-store/utils'; -import { INITIAL_LEAF, Pedersen, SHA256, StandardTree } from '@aztec/merkle-tree'; +import { INITIAL_LEAF, Pedersen, SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { jest } from '@jest/globals'; import { mock } from 'jest-mock-extended'; @@ -111,7 +111,7 @@ describe('server_world_state_synchronizer', () => { .map(() => Fr.random()); const tree = new StandardTree( openTmpStore(true), - new SHA256(), + new SHA256Trunc(), 'empty_subtree_in_hash', L1_TO_L2_MSG_SUBTREE_HEIGHT, ); diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts index 6a43188d8f1..583ceff28a8 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts @@ -7,7 +7,7 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { elapsed } from '@aztec/foundation/timer'; import { AztecKVStore, AztecSingleton } from '@aztec/kv-store'; import { openTmpStore } from '@aztec/kv-store/utils'; -import { SHA256, StandardTree } from '@aztec/merkle-tree'; +import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { HandleL2BlockAndMessagesResult, MerkleTreeOperations, MerkleTrees } from '../world-state-db/index.js'; import { MerkleTreeOperationsFacade } from '../world-state-db/merkle_tree_operations_facade.js'; @@ -240,7 +240,12 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { * @throws If the L1 to L2 messages do not hash to the block inHash. */ async #verifyMessagesHashToInHash(l1ToL2Messages: Fr[], inHash: Buffer) { - const tree = new StandardTree(openTmpStore(true), new SHA256(), 'temp_in_hash_check', L1_TO_L2_MSG_SUBTREE_HEIGHT); + const tree = new StandardTree( + openTmpStore(true), + new SHA256Trunc(), + 'temp_in_hash_check', + L1_TO_L2_MSG_SUBTREE_HEIGHT, + ); await tree.appendLeaves(l1ToL2Messages.map(msg => msg.toBuffer())); if (!tree.getRoot(true).equals(inHash)) { From fb897dbed55085421b5ae9ddcb0d28043c314f2b Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:52:30 -0700 Subject: [PATCH 12/36] feat: simplified bb Honk interface (#5319) Purpose of this PR is to clarify and simplify the bb interface for constructing and verifying Honk proofs (both UltraHonk and GoblinUltraHonk). A similar flow was previously achieved somewhat indirectly through the `goblin` class via `goblin.accumulate`. This was simply done for convenience a while back and is not the right thing long term. The new Honk flows are simplified and do not make use of anything like the `AcirComposer` used for Plonk. I have only added flows of the prove-AND-verify variety, i.e. more logic will be needed in order to separate out the proving and verifying (a la the prove-THEN-verify flows for Plonk). This includes serialization of proving and verification keys. --- barretenberg/acir_tests/Dockerfile.bb | 7 +- barretenberg/acir_tests/Dockerfile.bb.js | 4 +- .../flows/accumulate_and_verify_goblin.sh | 6 -- .../prove_and_verify_goblin_ultra_honk.sh | 6 ++ .../flows/prove_and_verify_ultra_honk.sh | 6 ++ barretenberg/cpp/src/barretenberg/bb/main.cpp | 54 ++++++++------- .../dsl/acir_format/acir_format.cpp | 42 ++++++++++-- .../barretenberg/dsl/acir_proofs/c_bind.cpp | 47 +++++++------ .../barretenberg/dsl/acir_proofs/c_bind.hpp | 24 +++---- .../dsl/acir_proofs/goblin_acir_composer.cpp | 19 ------ .../dsl/acir_proofs/goblin_acir_composer.hpp | 16 ----- .../goblin_ultra_circuit_builder.hpp | 2 +- barretenberg/exports.json | 46 ++++++------- barretenberg/ts/src/barretenberg_api/index.ts | 68 +++++++++---------- barretenberg/ts/src/main.ts | 46 ++++++++----- 15 files changed, 206 insertions(+), 187 deletions(-) delete mode 100755 barretenberg/acir_tests/flows/accumulate_and_verify_goblin.sh create mode 100755 barretenberg/acir_tests/flows/prove_and_verify_goblin_ultra_honk.sh create mode 100755 barretenberg/acir_tests/flows/prove_and_verify_ultra_honk.sh diff --git a/barretenberg/acir_tests/Dockerfile.bb b/barretenberg/acir_tests/Dockerfile.bb index f7123707612..60144b8a707 100644 --- a/barretenberg/acir_tests/Dockerfile.bb +++ b/barretenberg/acir_tests/Dockerfile.bb @@ -10,9 +10,10 @@ COPY . . # Run every acir test through native bb build prove_then_verify flow for UltraPlonk. # This ensures we test independent pk construction through real/garbage witness data paths. RUN FLOW=prove_then_verify ./run_acir_tests.sh -# This flow is essentially the GoblinUltraHonk equivalent to the UltraPlonk "prove and verify". (This functionality is -# accessed via the goblin "accumulate" mechanism). -RUN FLOW=accumulate_and_verify_goblin ./run_acir_tests.sh +# Construct and verify a UltraHonk proof for all acir programs +RUN FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh +# Construct and verify a Goblin UltraHonk (GUH) proof for a single arbitrary program +RUN FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array # This is a "full" Goblin flow. It constructs and verifies four proofs: GoblinUltraHonk, ECCVM, Translator, and merge RUN FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array # Run 1_mul through native bb build, all_cmds flow, to test all cli args. diff --git a/barretenberg/acir_tests/Dockerfile.bb.js b/barretenberg/acir_tests/Dockerfile.bb.js index d797fe8bed9..e0838949964 100644 --- a/barretenberg/acir_tests/Dockerfile.bb.js +++ b/barretenberg/acir_tests/Dockerfile.bb.js @@ -15,8 +15,10 @@ COPY . . ENV VERBOSE=1 # Run double_verify_proof through bb.js on node to check 512k support. RUN BIN=../ts/dest/node/main.js FLOW=prove_then_verify ./run_acir_tests.sh double_verify_proof +# Run a single arbitrary test not involving recursion through bb.js for UltraHonk +RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_ultra_honk ./run_acir_tests.sh 6_array # Run a single arbitrary test not involving recursion through bb.js for GoblinUltraHonk -RUN BIN=../ts/dest/node/main.js FLOW=accumulate_and_verify_goblin ./run_acir_tests.sh 6_array +RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin_ultra_honk ./run_acir_tests.sh 6_array # Run a single arbitrary test not involving recursion through bb.js for full Goblin RUN BIN=../ts/dest/node/main.js FLOW=prove_and_verify_goblin ./run_acir_tests.sh 6_array # Run 1_mul through bb.js build, all_cmds flow, to test all cli args. diff --git a/barretenberg/acir_tests/flows/accumulate_and_verify_goblin.sh b/barretenberg/acir_tests/flows/accumulate_and_verify_goblin.sh deleted file mode 100755 index a89e1a1dba1..00000000000 --- a/barretenberg/acir_tests/flows/accumulate_and_verify_goblin.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -set -eu - -VFLAG=${VERBOSE:+-v} - -$BIN accumulate_and_verify_goblin $VFLAG -c $CRS_PATH -b ./target/acir.gz \ No newline at end of file diff --git a/barretenberg/acir_tests/flows/prove_and_verify_goblin_ultra_honk.sh b/barretenberg/acir_tests/flows/prove_and_verify_goblin_ultra_honk.sh new file mode 100755 index 00000000000..a8a72924898 --- /dev/null +++ b/barretenberg/acir_tests/flows/prove_and_verify_goblin_ultra_honk.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu + +VFLAG=${VERBOSE:+-v} + +$BIN prove_and_verify_goblin_ultra_honk $VFLAG -c $CRS_PATH -b ./target/acir.gz \ No newline at end of file diff --git a/barretenberg/acir_tests/flows/prove_and_verify_ultra_honk.sh b/barretenberg/acir_tests/flows/prove_and_verify_ultra_honk.sh new file mode 100755 index 00000000000..7b6f0384796 --- /dev/null +++ b/barretenberg/acir_tests/flows/prove_and_verify_ultra_honk.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu + +VFLAG=${VERBOSE:+-v} + +$BIN prove_and_verify_ultra_honk $VFLAG -c $CRS_PATH -b ./target/acir.gz \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index 17c465945f1..34e4ef0fe4c 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -128,40 +128,41 @@ bool proveAndVerify(const std::string& bytecodePath, const std::string& witnessP } /** - * @brief Constructs and verifies a Honk proof for an ACIR circuit via the Goblin accumulate mechanism + * @brief Constructs and verifies a Honk proof for an acir-generated circuit * - * Communication: - * - proc_exit: A boolean value is returned indicating whether the proof is valid. - * an exit code of 0 will be returned for success and 1 for failure. - * - * @param bytecodePath Path to the file containing the serialized acir constraint system - * @param witnessPath Path to the file containing the serialized witness - * @return verified + * @tparam Flavor + * @param bytecodePath Path to serialized acir circuit data + * @param witnessPath Path to serialized acir witness data */ -bool accumulateAndVerifyGoblin(const std::string& bytecodePath, const std::string& witnessPath) +template bool proveAndVerifyHonk(const std::string& bytecodePath, const std::string& witnessPath) { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): Don't hardcode dyadic circuit size. Currently set - // to max circuit size present in acir tests suite. - size_t hardcoded_bn254_dyadic_size_hack = 1 << 19; - init_bn254_crs(hardcoded_bn254_dyadic_size_hack); - size_t hardcoded_grumpkin_dyadic_size_hack = 1 << 10; // For eccvm only - init_grumpkin_crs(hardcoded_grumpkin_dyadic_size_hack); + using Builder = Flavor::CircuitBuilder; + using Prover = UltraProver_; + using Verifier = UltraVerifier_; + using VerificationKey = Flavor::VerificationKey; // Populate the acir constraint system and witness from gzipped data auto constraint_system = get_constraint_system(bytecodePath); auto witness = get_witness(witnessPath); - // Instantiate a Goblin acir composer and construct a bberg circuit from the acir representation - acir_proofs::GoblinAcirComposer acir_composer; - acir_composer.create_circuit(constraint_system, witness); + // Construct a bberg circuit from the acir representation + auto builder = acir_format::create_circuit(constraint_system, 0, witness); - // Call accumulate to generate a GoblinUltraHonk proof - auto proof = acir_composer.accumulate(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): Add a buffer to the expected circuit size to + // account for the addition of "gates to ensure nonzero polynomials" (in Honk only). + const size_t additional_gates_buffer = 15; // conservatively large to be safe + size_t srs_size = builder.get_circuit_subgroup_size(builder.get_total_circuit_size() + additional_gates_buffer); + init_bn254_crs(srs_size); - // Verify the GoblinUltraHonk proof - auto verified = acir_composer.verify_accumulator(proof); + // Construct Honk proof + Prover prover{ builder }; + auto proof = prover.construct_proof(); - return verified; + // Verify Honk proof + auto verification_key = std::make_shared(prover.instance->proving_key); + Verifier verifier{ verification_key }; + + return verifier.verify_proof(proof); } /** @@ -569,8 +570,11 @@ int main(int argc, char* argv[]) if (command == "prove_and_verify") { return proveAndVerify(bytecode_path, witness_path) ? 0 : 1; } - if (command == "accumulate_and_verify_goblin") { - return accumulateAndVerifyGoblin(bytecode_path, witness_path) ? 0 : 1; + if (command == "prove_and_verify_ultra_honk") { + return proveAndVerifyHonk(bytecode_path, witness_path) ? 0 : 1; + } + if (command == "prove_and_verify_goblin_ultra_honk") { + return proveAndVerifyHonk(bytecode_path, witness_path) ? 0 : 1; } if (command == "prove_and_verify_goblin") { return proveAndVerifyGoblin(bytecode_path, witness_path) ? 0 : 1; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index f37d1f0bdfc..d8b1e2fdeb7 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -1,5 +1,6 @@ #include "acir_format.hpp" #include "barretenberg/common/log.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include @@ -202,7 +203,7 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo } /** - * @brief Create a circuit from acir constraints and optionally a witness + * @brief Specialization for creating Ultra circuit from acir constraints and optionally a witness * * @tparam Builder * @param constraint_system @@ -210,8 +211,8 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo * @param witness * @return Builder */ -template -Builder create_circuit(const AcirFormat& constraint_system, size_t size_hint, WitnessVector const& witness) +template <> +UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, size_t size_hint, WitnessVector const& witness) { Builder builder{ size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, constraint_system.recursive @@ -221,11 +222,38 @@ Builder create_circuit(const AcirFormat& constraint_system, size_t size_hint, Wi build_constraints(builder, constraint_system, has_valid_witness_assignments); return builder; -} +}; + +/** + * @brief Specialization for creating GoblinUltra circuit from acir constraints and optionally a witness + * + * @tparam Builder + * @param constraint_system + * @param size_hint + * @param witness + * @return Builder + */ +template <> +GoblinUltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, + [[maybe_unused]] size_t size_hint, + WitnessVector const& witness) +{ + // Construct a builder using the witness and public input data from acir and with the goblin-owned op_queue + auto op_queue = std::make_shared(); // instantiate empty op_queue + auto builder = + GoblinUltraCircuitBuilder{ op_queue, witness, constraint_system.public_inputs, constraint_system.varnum }; + + // Populate constraints in the builder via the data in constraint_system + bool has_valid_witness_assignments = !witness.empty(); + acir_format::build_constraints(builder, constraint_system, has_valid_witness_assignments); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/817): Add some arbitrary op gates to ensure the + // associated polynomials are non-zero and to give ECCVM and Translator some ECC ops to process. + MockCircuits::construct_goblin_ecc_op_circuit(builder); + + return builder; +}; -template UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, - size_t size_hint, - WitnessVector const& witness); template void build_constraints(GoblinUltraCircuitBuilder&, AcirFormat const&, bool); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp index 7fc9eff28f3..c867bd24847 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.cpp @@ -62,21 +62,38 @@ WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, *out = to_heap_buffer(proof_data); } -WASM_EXPORT void acir_goblin_accumulate(in_ptr acir_composer_ptr, - uint8_t const* acir_vec, - uint8_t const* witness_vec, - uint8_t** out) +WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* acir_vec, uint8_t const* witness_vec, bool* result) { - auto acir_composer = reinterpret_cast(*acir_composer_ptr); auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec)); auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); - acir_composer->create_circuit(constraint_system, witness); - auto proof = acir_composer->accumulate(); - auto proof_data_buf = to_buffer( - proof); // template parameter needs to be set so that vector deserialization from - // buffer, which reads the size at the beginning can be done properly - *out = to_heap_buffer(proof_data_buf); + auto builder = acir_format::create_circuit(constraint_system, 0, witness); + + UltraProver prover{ builder }; + auto proof = prover.construct_proof(); + + auto verification_key = std::make_shared(prover.instance->proving_key); + UltraVerifier verifier{ verification_key }; + + *result = verifier.verify_proof(proof); +} + +WASM_EXPORT void acir_prove_and_verify_goblin_ultra_honk(uint8_t const* acir_vec, + uint8_t const* witness_vec, + bool* result) +{ + auto constraint_system = acir_format::circuit_buf_to_acir_format(from_buffer>(acir_vec)); + auto witness = acir_format::witness_buf_to_witness_data(from_buffer>(witness_vec)); + + auto builder = acir_format::create_circuit(constraint_system, 0, witness); + + GoblinUltraProver prover{ builder }; + auto proof = prover.construct_proof(); + + auto verification_key = std::make_shared(prover.instance->proving_key); + GoblinUltraVerifier verifier{ verification_key }; + + *result = verifier.verify_proof(proof); } WASM_EXPORT void acir_goblin_prove(in_ptr acir_composer_ptr, @@ -127,14 +144,6 @@ WASM_EXPORT void acir_get_proving_key(in_ptr acir_composer_ptr, uint8_t const* a *out = to_heap_buffer(to_buffer(*pk)); } -WASM_EXPORT void acir_goblin_verify_accumulator(in_ptr acir_composer_ptr, uint8_t const* proof_buf, bool* result) -{ - auto acir_composer = reinterpret_cast(*acir_composer_ptr); - auto proof_data_buf = from_buffer>(proof_buf); - auto proof = from_buffer>(proof_data_buf); - *result = acir_composer->verify_accumulator(proof); -} - WASM_EXPORT void acir_goblin_verify(in_ptr acir_composer_ptr, uint8_t const* proof_buf, bool* result) { auto acir_composer = reinterpret_cast(*acir_composer_ptr); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp index 4dfc3259947..1c624c96ef3 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/c_bind.hpp @@ -34,14 +34,20 @@ WASM_EXPORT void acir_create_proof(in_ptr acir_composer_ptr, uint8_t** out); /** - * @brief Perform the goblin accumulate operation - * @details Constructs a GUH proof and possibly handles transcript merge logic + * @brief Construct and verify an UltraHonk proof * */ -WASM_EXPORT void acir_goblin_accumulate(in_ptr acir_composer_ptr, - uint8_t const* constraint_system_buf, - uint8_t const* witness_buf, - uint8_t** out); +WASM_EXPORT void acir_prove_and_verify_ultra_honk(uint8_t const* constraint_system_buf, + uint8_t const* witness_buf, + bool* result); + +/** + * @brief Construct and verify a GoblinUltraHonk proof + * + */ +WASM_EXPORT void acir_prove_and_verify_goblin_ultra_honk(uint8_t const* constraint_system_buf, + uint8_t const* witness_buf, + bool* result); /** * @brief Construct a full goblin proof @@ -63,12 +69,6 @@ WASM_EXPORT void acir_get_proving_key(in_ptr acir_composer_ptr, uint8_t const* a WASM_EXPORT void acir_verify_proof(in_ptr acir_composer_ptr, uint8_t const* proof_buf, bool* result); -/** - * @brief Verifies a GUH proof produced during goblin accumulation - * - */ -WASM_EXPORT void acir_goblin_verify_accumulator(in_ptr acir_composer_ptr, uint8_t const* proof_buf, bool* result); - /** * @brief Verifies a full goblin proof (and the GUH proof produced by accumulation) * diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.cpp index a757d2661f9..5d754a168a7 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.cpp @@ -21,25 +21,6 @@ void GoblinAcirComposer::create_circuit(acir_format::AcirFormat& constraint_syst MockCircuits::construct_goblin_ecc_op_circuit(builder_); } -std::vector GoblinAcirComposer::accumulate() -{ - // // Construct a GUH proof for the circuit via the accumulate mechanism - // return goblin.accumulate_for_acir(builder_); - - // Construct one final GUH proof via the accumulate mechanism - std::vector ultra_proof = goblin.accumulate_for_acir(builder_); - - // Construct a Goblin proof (ECCVM, Translator, Merge); result stored internally - goblin.prove_for_acir(); - - return ultra_proof; -} - -bool GoblinAcirComposer::verify_accumulator(std::vector const& proof) -{ - return goblin.verify_accumulator_for_acir(proof); -} - std::vector GoblinAcirComposer::accumulate_and_prove() { // Construct one final GUH proof via the accumulate mechanism diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.hpp index a533cba1830..534df5d6e44 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/goblin_acir_composer.hpp @@ -24,22 +24,6 @@ class GoblinAcirComposer { */ void create_circuit(acir_format::AcirFormat& constraint_system, acir_format::WitnessVector& witness); - /** - * @brief Accumulate a circuit via Goblin - * @details For the present circuit, construct a GUH proof and the vkey needed to verify it - * - * @return std::vector The GUH proof bytes - */ - std::vector accumulate(); - - /** - * @brief Verify the Goblin accumulator (the GUH proof) using the vkey internal to Goblin - * - * @param proof - * @return bool Whether or not the proof was verified - */ - bool verify_accumulator(std::vector const& proof); - /** * @brief Accumulate a final circuit and construct a full Goblin proof * @details Accumulation means constructing a GUH proof of a single (final) circuit. A full Goblin proof consists of diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp index 31f824216f2..28bda7e6f6e 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp @@ -72,7 +72,7 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui */ GoblinUltraCircuitBuilder_(std::shared_ptr op_queue_in, auto& witness_values, - std::vector& public_inputs, + const std::vector& public_inputs, size_t varnum) : UltraCircuitBuilder_>(/*size_hint=*/0, witness_values, public_inputs, varnum) , op_queue(op_queue_in) diff --git a/barretenberg/exports.json b/barretenberg/exports.json index 13425b898cd..cffe8b8fd08 100644 --- a/barretenberg/exports.json +++ b/barretenberg/exports.json @@ -599,12 +599,28 @@ "isAsync": false }, { - "functionName": "acir_goblin_accumulate", + "functionName": "acir_prove_and_verify_ultra_honk", "inArgs": [ { - "name": "acir_composer_ptr", - "type": "in_ptr" + "name": "constraint_system_buf", + "type": "const uint8_t *" }, + { + "name": "witness_buf", + "type": "const uint8_t *" + } + ], + "outArgs": [ + { + "name": "result", + "type": "bool *" + } + ], + "isAsync": false + }, + { + "functionName": "acir_prove_and_verify_goblin_ultra_honk", + "inArgs": [ { "name": "constraint_system_buf", "type": "const uint8_t *" @@ -616,8 +632,8 @@ ], "outArgs": [ { - "name": "out", - "type": "uint8_t **" + "name": "result", + "type": "bool *" } ], "isAsync": false @@ -728,26 +744,6 @@ ], "isAsync": false }, - { - "functionName": "acir_goblin_verify_accumulator", - "inArgs": [ - { - "name": "acir_composer_ptr", - "type": "in_ptr" - }, - { - "name": "proof_buf", - "type": "const uint8_t *" - } - ], - "outArgs": [ - { - "name": "result", - "type": "bool *" - } - ], - "isAsync": false - }, { "functionName": "acir_goblin_verify", "inArgs": [ diff --git a/barretenberg/ts/src/barretenberg_api/index.ts b/barretenberg/ts/src/barretenberg_api/index.ts index f74134d5467..05d6568cdb7 100644 --- a/barretenberg/ts/src/barretenberg_api/index.ts +++ b/barretenberg/ts/src/barretenberg_api/index.ts @@ -404,15 +404,23 @@ export class BarretenbergApi { return out[0]; } - async acirGoblinAccumulate( - acirComposerPtr: Ptr, - constraintSystemBuf: Uint8Array, - witnessBuf: Uint8Array, - ): Promise { - const inArgs = [acirComposerPtr, constraintSystemBuf, witnessBuf].map(serializeBufferable); - const outTypes: OutputType[] = [BufferDeserializer()]; + async acirProveAndVerifyUltraHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Promise { + const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + const outTypes: OutputType[] = [BoolDeserializer()]; + const result = await this.wasm.callWasmExport( + 'acir_prove_and_verify_ultra_honk', + inArgs, + outTypes.map(t => t.SIZE_IN_BYTES), + ); + const out = result.map((r, i) => outTypes[i].fromBuffer(r)); + return out[0]; + } + + async acirProveAndVerifyGoblinUltraHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Promise { + const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + const outTypes: OutputType[] = [BoolDeserializer()]; const result = await this.wasm.callWasmExport( - 'acir_goblin_accumulate', + 'acir_prove_and_verify_goblin_ultra_honk', inArgs, outTypes.map(t => t.SIZE_IN_BYTES), ); @@ -496,18 +504,6 @@ export class BarretenbergApi { return out[0]; } - async acirGoblinVerifyAccumulator(acirComposerPtr: Ptr, proofBuf: Uint8Array): Promise { - const inArgs = [acirComposerPtr, proofBuf].map(serializeBufferable); - const outTypes: OutputType[] = [BoolDeserializer()]; - const result = await this.wasm.callWasmExport( - 'acir_goblin_verify_accumulator', - inArgs, - outTypes.map(t => t.SIZE_IN_BYTES), - ); - const out = result.map((r, i) => outTypes[i].fromBuffer(r)); - return out[0]; - } - async acirGoblinVerify(acirComposerPtr: Ptr, proofBuf: Uint8Array): Promise { const inArgs = [acirComposerPtr, proofBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; @@ -948,11 +944,23 @@ export class BarretenbergApiSync { return out[0]; } - acirGoblinAccumulate(acirComposerPtr: Ptr, constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): Uint8Array { - const inArgs = [acirComposerPtr, constraintSystemBuf, witnessBuf].map(serializeBufferable); - const outTypes: OutputType[] = [BufferDeserializer()]; + acirProveAndVerifyUltraHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): boolean { + const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + const outTypes: OutputType[] = [BoolDeserializer()]; + const result = this.wasm.callWasmExport( + 'acir_prove_and_verify_ultra_honk', + inArgs, + outTypes.map(t => t.SIZE_IN_BYTES), + ); + const out = result.map((r, i) => outTypes[i].fromBuffer(r)); + return out[0]; + } + + acirProveAndVerifyGoblinUltraHonk(constraintSystemBuf: Uint8Array, witnessBuf: Uint8Array): boolean { + const inArgs = [constraintSystemBuf, witnessBuf].map(serializeBufferable); + const outTypes: OutputType[] = [BoolDeserializer()]; const result = this.wasm.callWasmExport( - 'acir_goblin_accumulate', + 'acir_prove_and_verify_goblin_ultra_honk', inArgs, outTypes.map(t => t.SIZE_IN_BYTES), ); @@ -1032,18 +1040,6 @@ export class BarretenbergApiSync { return out[0]; } - acirGoblinVerifyAccumulator(acirComposerPtr: Ptr, proofBuf: Uint8Array): boolean { - const inArgs = [acirComposerPtr, proofBuf].map(serializeBufferable); - const outTypes: OutputType[] = [BoolDeserializer()]; - const result = this.wasm.callWasmExport( - 'acir_goblin_verify_accumulator', - inArgs, - outTypes.map(t => t.SIZE_IN_BYTES), - ); - const out = result.map((r, i) => outTypes[i].fromBuffer(r)); - return out[0]; - } - acirGoblinVerify(acirComposerPtr: Ptr, proofBuf: Uint8Array): boolean { const inArgs = [acirComposerPtr, proofBuf].map(serializeBufferable); const outTypes: OutputType[] = [BoolDeserializer()]; diff --git a/barretenberg/ts/src/main.ts b/barretenberg/ts/src/main.ts index ec974fd1c35..6a7d7922f52 100755 --- a/barretenberg/ts/src/main.ts +++ b/barretenberg/ts/src/main.ts @@ -129,28 +129,29 @@ export async function proveAndVerify(bytecodePath: string, witnessPath: string, /* eslint-enable camelcase */ } -export async function accumulateAndVerifyGoblin(bytecodePath: string, witnessPath: string, crsPath: string) { +export async function proveAndVerifyUltraHonk(bytecodePath: string, witnessPath: string, crsPath: string) { /* eslint-disable camelcase */ - const acir_test = path.basename(process.cwd()); - - const { api, acirComposer, circuitSize, subgroupSize } = await initGoblin(bytecodePath, crsPath); + const { api } = await init(bytecodePath, crsPath); try { - debug(`In accumulateAndVerifyGoblin:`); const bytecode = getBytecode(bytecodePath); const witness = getWitness(witnessPath); - writeBenchmark('gate_count', circuitSize, { acir_test, threads }); - writeBenchmark('subgroup_size', subgroupSize, { acir_test, threads }); + const verified = await api.acirProveAndVerifyUltraHonk(bytecode, witness); + return verified; + } finally { + await api.destroy(); + } + /* eslint-enable camelcase */ +} - debug(`acirGoblinAccumulate()`); - const proofTimer = new Timer(); - const proof = await api.acirGoblinAccumulate(acirComposer, bytecode, witness); - writeBenchmark('proof_construction_time', proofTimer.ms(), { acir_test, threads }); +export async function proveAndVerifyGoblinUltraHonk(bytecodePath: string, witnessPath: string, crsPath: string) { + /* eslint-disable camelcase */ + const { api } = await init(bytecodePath, crsPath); + try { + const bytecode = getBytecode(bytecodePath); + const witness = getWitness(witnessPath); - debug(`acirVerifyGoblinProof()`); - const verified = await api.acirGoblinVerifyAccumulator(acirComposer, proof); - debug(`verified: ${verified}`); - console.log({ verified }); + const verified = await api.acirProveAndVerifyGoblinUltraHonk(bytecode, witness); return verified; } finally { await api.destroy(); @@ -380,13 +381,24 @@ program }); program - .command('accumulate_and_verify_goblin') + .command('prove_and_verify_ultra_honk') + .description('Generate an UltraHonk proof and verify it. Process exits with success or failure code.') + .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/acir.gz') + .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') + .action(async ({ bytecodePath, witnessPath, crsPath }) => { + handleGlobalOptions(); + const result = await proveAndVerifyUltraHonk(bytecodePath, witnessPath, crsPath); + process.exit(result ? 0 : 1); + }); + +program + .command('prove_and_verify_goblin_ultra_honk') .description('Generate a GUH proof and verify it. Process exits with success or failure code.') .option('-b, --bytecode-path ', 'Specify the bytecode path', './target/acir.gz') .option('-w, --witness-path ', 'Specify the witness path', './target/witness.gz') .action(async ({ bytecodePath, witnessPath, crsPath }) => { handleGlobalOptions(); - const result = await accumulateAndVerifyGoblin(bytecodePath, witnessPath, crsPath); + const result = await proveAndVerifyGoblinUltraHonk(bytecodePath, witnessPath, crsPath); process.exit(result ? 0 : 1); }); From 8cf742d7bb108e3a50f1b52189a0b6da9867f4a7 Mon Sep 17 00:00:00 2001 From: maramihali Date: Thu, 21 Mar 2024 22:00:15 +0000 Subject: [PATCH 13/36] feat: ZeroMorph working with IPA and integration with ECCVM (#5246) Resolves https://github.com/AztecProtocol/barretenberg/issues/769. Resolves https://github.com/AztecProtocol/barretenberg/issues/782. Generalise Zeromorph further to be able to instantiate with both KZG and IPA and switch ECCVM to use Zeromorph + IPA. This PR also fixes a small inconsistency in Zeromorph where we assumed that first element of the SRS is always going to be [1]_1 which is not the case if we work on Grumpkin. Unskip and complete eccvm transcript tests. --- .../benchmark/ipa_bench/ipa.bench.cpp | 2 +- .../commitment_schemes/ipa/ipa.fuzzer.cpp | 2 +- .../commitment_schemes/ipa/ipa.hpp | 37 ++--- .../commitment_schemes/ipa/ipa.test.cpp | 15 +- .../commitment_schemes/kzg/kzg.hpp | 22 --- .../commitment_schemes/kzg/kzg.test.cpp | 8 +- .../zeromorph/zeromorph.hpp | 140 ++++++++++++++---- .../zeromorph/zeromorph.test.cpp | 75 +++++++--- .../src/barretenberg/eccvm/eccvm_prover.cpp | 114 ++------------ .../src/barretenberg/eccvm/eccvm_prover.hpp | 15 +- .../eccvm/eccvm_transcript.test.cpp | 71 +++++---- .../src/barretenberg/eccvm/eccvm_verifier.cpp | 83 ++--------- .../cpp/src/barretenberg/flavor/ecc_vm.hpp | 134 +++++++++++------ .../src/barretenberg/flavor/goblin_ultra.hpp | 6 +- .../cpp/src/barretenberg/flavor/ultra.hpp | 6 +- .../protogalaxy/decider_verifier.cpp | 3 +- .../verifier/ultra_recursive_verifier.cpp | 14 +- .../goblin_translator_verifier.cpp | 1 - .../ultra_honk/merge_verifier.cpp | 4 +- .../ultra_honk/ultra_verifier.cpp | 11 +- 20 files changed, 377 insertions(+), 386 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp index 772b9130dfd..2f4b2cd88f4 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp @@ -60,7 +60,7 @@ void ipa_verify(State& state) noexcept auto verifier_transcript = std::make_shared(prover_transcript->proof_data); state.ResumeTiming(); - auto result = IPA::verify(vk, opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(vk, opening_claim, verifier_transcript); ASSERT(result); } } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp index f6d98bbd7fa..cebb8c59c7a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp @@ -32,7 +32,7 @@ class ProxyCaller { const OpeningClaim& opening_claim, const std::shared_ptr& transcript) { - return IPA::verify_internal(vk, opening_claim, transcript); + return IPA::reduce_verify_internal(vk, opening_claim, transcript); } }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp index dfe6f6d94f0..ca7872285c6 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp @@ -35,7 +35,7 @@ namespace bb { * * @remark IPA is not a very intuitive algorithm, so here are a few things that might help internalize it: * - *1. Originally we have two vectors \f$\vec{a}\f$ and \f$\vec{b}\f$, which the product of which we want to prove, but + *1. Originally we have two vectors \f$\vec{a}\f$ and \f$\vec{b}\f$, whose product we want to prove, but *the prover can't just send vector \f$\vec{a}\f$ to the verifier, it can only provide a commitment \f$\langle\vec{a},\vec{G}\rangle\f$ *2. The verifier computes the \f$C'=C+\langle\vec{a},\vec{b}\rangle\cdot U\f$ to "bind" together the @@ -50,8 +50,8 @@ namespace bb { \alpha^{-1}\langle\vec{a}_{low},\vec{b}_{high}\rangle+\alpha \langle \vec{a}_{high},\vec{b}_{low}\rangle + \langle\vec{a}_{high},\vec{b}_{high}\rangle= \langle\vec{a},\vec{b}\rangle+\alpha^{-1}\langle\vec{a}_{low},\vec{b}_{high}\rangle+\alpha \langle - \vec{a}_{high},\vec{b}_{low}\rangle\f$, so if we provide commitments to - \f$\langle\vec{a}_{low},\vec{b}_{high}\rangle\f$ and \f$\langle \vec{a}_{high},\vec{b}_{low}\rangle\f$ the verifier + \vec{a}_{high},\vec{b}_{low}\rangle\f$, so if we provide commitments to the cross-terms + \f$\langle\vec{a}_{low},\vec{b}_{high}\rangle\f$ and \f$\langle \vec{a}_{high},\vec{b}_{low}\rangle\f$, the verifier can reduce initial commitment to the result \f$\langle \vec{a},\vec{b}\rangle U\f$ to the new commitment \f$\langle \vec{a}_{new},\vec{b}_{new}\rangle U\f$ *5. Analogously, if \f$\vec{G}_{new}=\vec{G}_{low}+\alpha^{-1}\vec{G}_{high}\f$, then we can reduce the initial @@ -71,14 +71,16 @@ namespace bb { * The old version of documentation is available at Old IPA documentation */ -template class IPA { - // clang-fromat on +template class IPA { + public: + using Curve = Curve_; using Fr = typename Curve::ScalarField; using GroupElement = typename Curve::Element; using Commitment = typename Curve::AffineElement; using CK = CommitmentKey; using VK = VerifierCommitmentKey; using Polynomial = bb::Polynomial; + using VerifierAccumulator = bool; // These allow access to internal functions so that we can never use a mock transcript unless it's fuzzing or testing of IPA specifically #ifdef IPA_TEST @@ -107,8 +109,10 @@ template class IPA { *1. Send the degree of \f$f(x)\f$ plus one, equal to \f$d\f$ to the verifier *2. Receive the generator challenge \f$u\f$ from the verifier. If it is zero, abort *3. Compute the auxiliary generator \f$U=u\cdot G\f$, where \f$G\f$ is a generator of \f$E(\mathbb{F}_p)\f$​ - *4. Set \f$\vec{G}_{k}=\vec{G}\f$, \f$\vec{a}_{k}=\vec{p}\f$ - *5. Compute the vector \f$\vec{b}_{k}=(1,\beta,\beta^2,...,\beta^{d-1})\f$ + *4. Set \f$\vec{G}_{k}=\vec{G}\f$, \f$\vec{a}_{k}=\vec{p}\f$ where \f$vec{p}\f$ represent the polynomial's + *coefficients + . *5. Compute the vector \f$\vec{b}_{k}=(1,\beta,\beta^2,...,\beta^{d-1})\f$ where \f$p(\beta)$\f is the + evaluation we wish to prove. *6. Perform \f$k\f$ rounds (for \f$i \in \{k,...,1\}\f$) of: * 1. Compute \f$L_{i-1}=\langle\vec{a}_{i\_low},\vec{G}_{i\_high}\rangle+\langle\vec{a}_{i\_low},\vec{b}_{i\_high}\rangle\cdot @@ -328,13 +332,11 @@ template class IPA { *9. Receive \f$\vec{a}_{0}\f$ of length 1 *10. Compute \f$C_{right}=a_{0}G_{s}+a_{0}b_{0}U\f$ *11. Check that \f$C_{right} = C_0\f$. If they match, return true. Otherwise return false. - * - * */ template - static bool verify_internal(const std::shared_ptr& vk, - const OpeningClaim& opening_claim, - const std::shared_ptr& transcript) + static VerifierAccumulator reduce_verify_internal(const std::shared_ptr& vk, + const OpeningClaim& opening_claim, + const std::shared_ptr& transcript) { // Step 1. // Receive polynomial_degree + 1 = d from the prover @@ -352,7 +354,6 @@ template class IPA { auto aux_generator = Commitment::one() * generator_challenge; auto log_poly_degree = static_cast(numeric::get_msb(poly_length)); - // Step 3. // Compute C' = C + f(\beta) ⋅ U GroupElement C_prime = opening_claim.commitment + (aux_generator * opening_claim.opening_pair.evaluation); @@ -495,11 +496,13 @@ template class IPA { * *@remark The verification procedure documentation is in \link IPA::verify_internal verify_internal \endlink */ - static bool verify(const std::shared_ptr& vk, - const OpeningClaim& opening_claim, - const std::shared_ptr& transcript) + // TODO(https://github.com/AztecProtocol/barretenberg/issues/912): Return the proper VerifierAccumulator once + // implemented + static VerifierAccumulator reduce_verify(const std::shared_ptr& vk, + const OpeningClaim& opening_claim, + const std::shared_ptr& transcript) { - return verify_internal(vk, opening_claim, transcript); + return reduce_verify_internal(vk, opening_claim, transcript); } }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp index 87f14d5630c..4defedb4500 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp @@ -1,3 +1,4 @@ + #include "../gemini/gemini.hpp" #include "../shplonk/shplonk.hpp" #include "./mock_transcript.hpp" @@ -71,7 +72,7 @@ TEST_F(IPATest, OpenZeroPolynomial) // initialize verifier transcript from proof data auto verifier_transcript = std::make_shared(prover_transcript->proof_data); - auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); } @@ -96,7 +97,7 @@ TEST_F(IPATest, OpenAtZero) // initialize verifier transcript from proof data auto verifier_transcript = std::make_shared(prover_transcript->proof_data); - auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); } @@ -144,7 +145,7 @@ TEST_F(IPATest, ChallengesAreZero) auto new_random_vector = random_vector; new_random_vector[i] = Fr::zero(); transcript->initialize(new_random_vector, lrs, { uint256_t(n) }); - EXPECT_ANY_THROW(IPA::verify_internal(this->vk(), opening_claim, transcript)); + EXPECT_ANY_THROW(IPA::reduce_verify_internal(this->vk(), opening_claim, transcript)); } } @@ -186,7 +187,7 @@ TEST_F(IPATest, AIsZeroAfterOneRound) transcript->reset_indices(); // Verify - EXPECT_TRUE(IPA::verify_internal(this->vk(), opening_claim, transcript)); + EXPECT_TRUE(IPA::reduce_verify_internal(this->vk(), opening_claim, transcript)); } #endif } // namespace bb @@ -225,7 +226,7 @@ TEST_F(IPATest, Open) // initialize verifier transcript from proof data auto verifier_transcript = std::make_shared(prover_transcript->proof_data); - auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); EXPECT_EQ(prover_transcript->get_manifest(), verifier_transcript->get_manifest()); @@ -321,7 +322,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) const auto shplonk_verifier_claim = ShplonkVerifier::reduce_verification(this->vk(), gemini_verifier_claim, verifier_transcript); - bool verified = IPA::verify(this->vk(), shplonk_verifier_claim, verifier_transcript); + auto result = IPA::reduce_verify(this->vk(), shplonk_verifier_claim, verifier_transcript); - EXPECT_EQ(verified, true); + EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp index ce360d83949..c763f3a2ecf 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp @@ -46,27 +46,6 @@ template class KZG { prover_trancript->send_to_verifier("KZG:W", quotient_commitment); }; - /** - * @brief Computes the KZG verification for an opening claim of a single polynomial commitment - * - * @param vk is the verification key which has a pairing check function - * @param claim OpeningClaim ({r, v}, C) - * @return e(P₀,[1]₁)e(P₁,[x]₂)≡ [1]ₜ where - * - P₀ = C − v⋅[1]₁ + r⋅[x]₁ - * - P₁ = [Q(x)]₁ - */ - static bool verify(const std::shared_ptr& vk, - const OpeningClaim& claim, - const std::shared_ptr& verifier_transcript) - { - auto quotient_commitment = verifier_transcript->template receive_from_prover("KZG:W"); - auto lhs = claim.commitment - (GroupElement::one() * claim.opening_pair.evaluation) + - (quotient_commitment * claim.opening_pair.challenge); - auto rhs = -quotient_commitment; - - return vk->pairing_check(lhs, rhs); - }; - /** * @brief Computes the input points for the pairing check needed to verify a KZG opening claim of a single * polynomial commitment. This reduction is non-interactive and always succeeds. @@ -102,7 +81,6 @@ template class KZG { } auto P_1 = -quotient_commitment; - return { P_0, P_1 }; }; }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp index 4ec38c45561..5271e92b890 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp @@ -44,9 +44,9 @@ TYPED_TEST(KZGTest, single) KZG::compute_opening_proof(this->ck(), opening_pair, witness, prover_transcript); auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); - bool verified = KZG::verify(this->vk(), opening_claim, verifier_transcript); + auto pairing_points = KZG::reduce_verify(opening_claim, verifier_transcript); - EXPECT_EQ(verified, true); + EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); } /** @@ -170,11 +170,11 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) // KZG verifier: // aggregates inputs [Q] - [Q_z] and [W] into an 'accumulator' (can perform pairing check on result) - bool verified = KZG::verify(this->vk(), shplonk_verifier_claim, verifier_transcript); + auto pairing_points = KZG::reduce_verify(shplonk_verifier_claim, verifier_transcript); // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2) - EXPECT_EQ(verified, true); + EXPECT_EQ(this->vk()->pairing_check(pairing_points[0], pairing_points[1]), true); } } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index d3cedc565a6..4811d32407a 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -1,5 +1,7 @@ #pragma once +#include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/commitment_key.hpp" +#include "barretenberg/commitment_schemes/verification_key.hpp" #include "barretenberg/common/ref_span.hpp" #include "barretenberg/common/ref_vector.hpp" #include "barretenberg/common/zip_view.hpp" @@ -425,7 +427,6 @@ template class ZeroMorphProver_ { // Compute batched degree-check and ZM-identity quotient polynomial pi auto pi_polynomial = compute_batched_evaluation_and_degree_check_polynomial(zeta_x, Z_x, z_challenge); - // Compute opening proof for x_challenge using the underlying univariate PCS PCS::compute_opening_proof( commitment_key, { .challenge = x_challenge, .evaluation = FF(0) }, pi_polynomial, transcript); @@ -508,6 +509,7 @@ template class ZeroMorphVerifier_ { * * @note The concatenation term arises from an implementation detail in the Goblin Translator and is not part of the * conventional ZM protocol + * @param first_g1 first element in the SRS * @param f_commitments Commitments to unshifted polynomials [f_i] * @param g_commitments Commitments to to-be-shifted polynomials [g_i] * @param C_q_k Commitments to q_k @@ -518,7 +520,8 @@ template class ZeroMorphVerifier_ { * @param concatenation_groups_commitments * @return Commitment */ - static Commitment compute_C_Z_x(RefSpan f_commitments, + static Commitment compute_C_Z_x(Commitment first_g1, + RefSpan f_commitments, RefSpan g_commitments, std::span C_q_k, FF rho, @@ -541,11 +544,10 @@ template class ZeroMorphVerifier_ { if constexpr (Curve::is_stdlib_type) { auto builder = x_challenge.get_context(); scalars.emplace_back(FF(builder, -1) * batched_evaluation * x_challenge * phi_n_x); - commitments.emplace_back(Commitment::one(builder)); } else { scalars.emplace_back(FF(-1) * batched_evaluation * x_challenge * phi_n_x); - commitments.emplace_back(Commitment::one()); } + commitments.emplace_back(first_g1); // Add contribution: x * \sum_{i=0}^{m-1} \rho^i*[f_i] auto rho_pow = FF(1); @@ -626,23 +628,30 @@ template class ZeroMorphVerifier_ { } /** - * @brief Verify a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted - * polynomials g_i + * @brief Compute the univariate opening claim used in the last step of Zeromorph to verify the univariate PCS + * evaluation. * - * @param commitments Commitments to polynomials f_i and g_i (unshifted and to-be-shifted) - * @param claimed_evaluations Claimed evaluations v_i = f_i(u) and w_i = h_i(u) = g_i_shifted(u) - * @param multivariate_challenge Challenge point u + * @param unshifted_commitments + * @param to_be_shifted_commitments + * @param unshifted_evaluations + * @param shifted_evaluations + * @param multivariate_challenge + * @param first_g1 * @param transcript - * @return std::array Inputs to the final pairing check + * @param concatenation_group_commitments + * @param concatenated_evaluations + * @return OpeningClaim */ - static VerifierAccumulator verify(RefSpan unshifted_commitments, - RefSpan to_be_shifted_commitments, - RefSpan unshifted_evaluations, - RefSpan shifted_evaluations, - std::span multivariate_challenge, - auto& transcript, - const std::vector>& concatenation_group_commitments = {}, - RefSpan concatenated_evaluations = {}) + static OpeningClaim compute_univariate_evaluation_opening_claim( + RefSpan unshifted_commitments, + RefSpan to_be_shifted_commitments, + RefSpan unshifted_evaluations, + RefSpan shifted_evaluations, + std::span multivariate_challenge, + Commitment first_g1, + auto& transcript, + const std::vector>& concatenation_group_commitments = {}, + RefSpan concatenated_evaluations = {}) { size_t log_N = multivariate_challenge.size(); FF rho = transcript->template get_challenge("rho"); @@ -683,7 +692,8 @@ template class ZeroMorphVerifier_ { auto C_zeta_x = compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); // Compute commitment C_{Z_x} - Commitment C_Z_x = compute_C_Z_x(unshifted_commitments, + Commitment C_Z_x = compute_C_Z_x(first_g1, + unshifted_commitments, to_be_shifted_commitments, C_q_k, rho, @@ -694,26 +704,102 @@ template class ZeroMorphVerifier_ { // Compute commitment C_{\zeta,Z} Commitment C_zeta_Z; + FF evaluation; if constexpr (Curve::is_stdlib_type) { // Express operation as a batch_mul in order to use Goblinization if available auto builder = z_challenge.get_context(); std::vector scalars = { FF(builder, 1), z_challenge }; std::vector points = { C_zeta_x, C_Z_x }; C_zeta_Z = Commitment::batch_mul(points, scalars); + evaluation = FF(builder, 0); } else { C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; + evaluation = FF(0); } - // Define the evaluation (always zero by construction in this case) for the PCS opening - FF evaluation{ 0 }; - if constexpr (Curve::is_stdlib_type) { // add builder if in circuit context - auto builder = z_challenge.get_context(); - evaluation = FF(builder, 0); + return { .opening_pair = { .challenge = x_challenge, .evaluation = evaluation }, .commitment = C_zeta_Z }; + } + + /** + * @brief Verify a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted + * polynomials g_i + * + * @param commitments Commitments to polynomials f_i and g_i (unshifted and to-be-shifted) + * @param claimed_evaluations Claimed evaluations v_i = f_i(u) and w_i = h_i(u) = g_i_shifted(u) + * @param multivariate_challenge Challenge point u + * @param transcript + * @return VerifierAccumulator Inputs to the final PCS verification check that will be accumulated + */ + static VerifierAccumulator verify(RefSpan unshifted_commitments, + RefSpan to_be_shifted_commitments, + RefSpan unshifted_evaluations, + RefSpan shifted_evaluations, + std::span multivariate_challenge, + auto& transcript, + const std::vector>& concatenation_group_commitments = {}, + RefSpan concatenated_evaluations = {}) + { + Commitment first_g1; + + if constexpr (Curve::is_stdlib_type) { + auto builder = multivariate_challenge[0].get_context(); + first_g1 = Commitment::one(builder); + } else { + first_g1 = Commitment::one(); } + auto opening_claim = compute_univariate_evaluation_opening_claim(unshifted_commitments, + to_be_shifted_commitments, + unshifted_evaluations, + shifted_evaluations, + multivariate_challenge, + first_g1, + transcript, + concatenation_group_commitments, + concatenated_evaluations); + return PCS::reduce_verify(opening_claim, transcript); + } - return PCS::reduce_verify( - { .opening_pair = { .challenge = x_challenge, .evaluation = evaluation }, .commitment = C_zeta_Z }, - transcript); + /** + * @brief Verify a set of multilinear evaluation claims for unshifted polynomials f_i and to-be-shifted + * polynomials g_i. + * + * @details Identical purpose as the function above but used when the verification of the PCS evaluation protocol + * requires the verification key prior to the last step that is accumulated. + * + * @param commitments Commitments to polynomials f_i and g_i (unshifted and to-be-shifted) + * @param claimed_evaluations Claimed evaluations v_i = f_i(u) and w_i = h_i(u) = g_i_shifted(u) + * @param multivariate_challenge Challenge point u + * @param transcript + * @return VerifierAccumulator Inputs to the final PCS verification check that will be accumulated + */ + static VerifierAccumulator verify(RefSpan unshifted_commitments, + RefSpan to_be_shifted_commitments, + RefSpan unshifted_evaluations, + RefSpan shifted_evaluations, + std::span multivariate_challenge, + const std::shared_ptr>& vk, + auto& transcript, + const std::vector>& concatenation_group_commitments = {}, + RefSpan concatenated_evaluations = {}) + { + Commitment first_g1; + // Retrieve the first element in the SRS [1]_1 which will be different depending on the curve we operate on + if constexpr (Curve::is_stdlib_type) { + auto builder = multivariate_challenge[0].get_context(); + first_g1 = Commitment(builder, vk->srs->get_first_g1()); + } else { + first_g1 = vk->srs->get_first_g1(); + } + auto opening_claim = compute_univariate_evaluation_opening_claim(unshifted_commitments, + to_be_shifted_commitments, + unshifted_evaluations, + shifted_evaluations, + multivariate_challenge, + first_g1, + transcript, + concatenation_group_commitments, + concatenated_evaluations); + return PCS::reduce_verify(vk, opening_claim, transcript); } }; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp index 7274300114e..3fcb56aa3af 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp @@ -1,5 +1,6 @@ #include "zeromorph.hpp" #include "../commitment_key.test.hpp" +#include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/commitment_schemes/kzg/kzg.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -14,6 +15,7 @@ template class ZeroMorphTest : public CommitmentTest; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; + using VerifierAccumulator = typename PCS::VerifierAccumulator; using ZeroMorphProver = ZeroMorphProver_; using ZeroMorphVerifier = ZeroMorphVerifier_; @@ -39,7 +41,7 @@ template class ZeroMorphTest : public CommitmentTest u_challenge = this->random_evaluation_point(log_N); @@ -90,15 +92,28 @@ template class ZeroMorphTest : public CommitmentTestvk()->pairing_check(pairing_points[0], pairing_points[1]); + VerifierAccumulator result; + bool verified = false; + if constexpr (std::same_as>) { + // Execute Verifier protocol without the need for vk prior the final check + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + verifier_transcript); + verified = this->vk()->pairing_check(result[0], result[1]); + } else { + // Execute Verifier protocol with vk + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + this->vk(), + verifier_transcript); + verified = result; + } // The prover and verifier manifests should agree EXPECT_EQ(prover_transcript->get_manifest(), verifier_transcript->get_manifest()); @@ -114,6 +129,7 @@ template class ZeroMorphWithConcatenationTest : public CommitmentTes using Polynomial = bb::Polynomial; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; + using VerifierAccumulator = typename PCS::VerifierAccumulator; using ZeroMorphProver = ZeroMorphProver_; using ZeroMorphVerifier = ZeroMorphVerifier_; @@ -243,27 +259,40 @@ template class ZeroMorphWithConcatenationTest : public CommitmentTes to_vector_of_ref_vectors(concatenation_groups)); auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); + VerifierAccumulator result; + if constexpr (std::same_as>) { + // Execute Verifier protocol without the need for vk prior the final check + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + verifier_transcript, + to_vector_of_ref_vectors(concatenation_groups_commitments), + RefVector(c_evaluations)); + verified = this->vk()->pairing_check(result[0], result[1]); - // Execute Verifier protocol - auto pairing_points = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted - RefVector(g_commitments), // to-be-shifted - RefVector(v_evaluations), // unshifted - RefVector(w_evaluations), // shifted - u_challenge, - verifier_transcript, - to_vector_of_ref_vectors(concatenation_groups_commitments), - RefVector(c_evaluations)); - - verified = this->vk()->pairing_check(pairing_points[0], pairing_points[1]); + } else { + // Execute Verifier protocol with vk + result = ZeroMorphVerifier::verify(RefVector(f_commitments), // unshifted + RefVector(g_commitments), // to-be-shifted + RefVector(v_evaluations), // unshifted + RefVector(w_evaluations), // shifted + u_challenge, + this->vk(), + verifier_transcript, + to_vector_of_ref_vectors(concatenation_groups_commitments), + RefVector(c_evaluations)); + verified = result; + } // The prover and verifier manifests should agree EXPECT_EQ(prover_transcript->get_manifest(), verifier_transcript->get_manifest()); - return verified; } }; -using PCSTypes = ::testing::Types>; +using PCSTypes = ::testing::Types, IPA>; TYPED_TEST_SUITE(ZeroMorphTest, PCSTypes); TYPED_TEST_SUITE(ZeroMorphWithConcatenationTest, PCSTypes); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index d7f8c7a6129..f7d367265ea 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -119,100 +119,19 @@ template void ECCVMProver_::execute_relation_chec } /** - * - Get rho challenge - * - Compute d+1 Fold polynomials and their evaluations. + * @brief Execute the ZeroMorph protocol to prove the multilinear evaluations produced by Sumcheck + * @details See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. * * */ -template void ECCVMProver_::execute_univariatization_round() +template void ECCVMProver_::execute_zeromorph_rounds() { - const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - - // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ - FF rho = transcript->template get_challenge("rho"); - std::vector rhos = gemini::powers_of_rho(rho, NUM_POLYNOMIALS); - - // Batch the unshifted polynomials and the to-be-shifted polynomials using ρ - Polynomial batched_poly_unshifted(key->circuit_size); // batched unshifted polynomials - size_t poly_idx = 0; // TODO(https://github.com/AztecProtocol/barretenberg/issues/391) zip - ASSERT(prover_polynomials.get_to_be_shifted().size() == prover_polynomials.get_shifted().size()); - - for (auto& unshifted_poly : prover_polynomials.get_unshifted()) { - ASSERT(poly_idx < rhos.size()); - batched_poly_unshifted.add_scaled(unshifted_poly, rhos[poly_idx]); - ++poly_idx; - } - - Polynomial batched_poly_to_be_shifted(key->circuit_size); // batched to-be-shifted polynomials - for (auto& to_be_shifted_poly : prover_polynomials.get_to_be_shifted()) { - ASSERT(poly_idx < rhos.size()); - batched_poly_to_be_shifted.add_scaled(to_be_shifted_poly, rhos[poly_idx]); - ++poly_idx; - }; - - // Compute d-1 polynomials Fold^(i), i = 1, ..., d-1. - gemini_polynomials = Gemini::compute_gemini_polynomials( - sumcheck_output.challenge, std::move(batched_poly_unshifted), std::move(batched_poly_to_be_shifted)); - - // Compute and add to trasnscript the commitments [Fold^(i)], i = 1, ..., d-1 - for (size_t l = 0; l < key->log_circuit_size - 1; ++l) { - transcript->send_to_verifier("Gemini:FOLD_" + std::to_string(l + 1), - commitment_key->commit(gemini_polynomials[l + 2])); - } -} - -/** - * - Do Fiat-Shamir to get "r" challenge - * - Compute remaining two partially evaluated Fold polynomials Fold_{r}^(0) and Fold_{-r}^(0). - * - Compute and aggregate opening pairs (challenge, evaluation) for each of d Fold polynomials. - * - Add d-many Fold evaluations a_i, i = 0, ..., d-1 to the transcript, excluding eval of Fold_{r}^(0) - * */ -template void ECCVMProver_::execute_pcs_evaluation_round() -{ - const FF r_challenge = transcript->template get_challenge("Gemini:r"); - gemini_output = Gemini::compute_fold_polynomial_evaluations( - sumcheck_output.challenge, std::move(gemini_polynomials), r_challenge); - - for (size_t l = 0; l < key->log_circuit_size; ++l) { - std::string label = "Gemini:a_" + std::to_string(l); - const auto& evaluation = gemini_output.opening_pairs[l + 1].evaluation; - transcript->send_to_verifier(label, evaluation); - } -} - -/** - * - Do Fiat-Shamir to get "nu" challenge. - * - Compute commitment [Q]_1 - * */ -template void ECCVMProver_::execute_shplonk_batched_quotient_round() -{ - nu_challenge = transcript->template get_challenge("Shplonk:nu"); - - batched_quotient_Q = - Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); - - // commit to Q(X) and add [Q] to the transcript - transcript->send_to_verifier("Shplonk:Q", commitment_key->commit(batched_quotient_Q)); -} - -/** - * - Do Fiat-Shamir to get "z" challenge. - * - Compute polynomial Q(X) - Q_z(X) - * */ -template void ECCVMProver_::execute_shplonk_partial_evaluation_round() -{ - const FF z_challenge = transcript->template get_challenge("Shplonk:z"); - - shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( - gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); -} -/** - * - Compute final PCS opening proof: - * - For KZG, this is the quotient commitment [W]_1 - * - For IPA, the vectors L and R - * */ -template void ECCVMProver_::execute_final_pcs_round() -{ - PCS::compute_opening_proof(commitment_key, shplonk_output.opening_pair, shplonk_output.witness, transcript); + ZeroMorph::prove(prover_polynomials.get_unshifted(), + prover_polynomials.get_to_be_shifted(), + sumcheck_output.claimed_evaluations.get_unshifted(), + sumcheck_output.claimed_evaluations.get_shifted(), + sumcheck_output.challenge, + commitment_key, + transcript); } /** @@ -266,7 +185,8 @@ template void ECCVMProver_::execute_transcript_co batching_scalar *= ipa_batching_challenge; } - // Compute a proof for the batched univariate opening + // TODO(https://github.com/AztecProtocol/barretenberg/issues/922): We are doing another round of IPA here with + // exactly the same labels and no domain separation so if/when labels are going to matter we are clashing. PCS::compute_opening_proof( commitment_key, { evaluation_challenge_x, batched_evaluation }, batched_univariate, transcript); @@ -294,15 +214,7 @@ template HonkProof& ECCVMProver_::construct_proof execute_relation_check_rounds(); - execute_univariatization_round(); - - execute_pcs_evaluation_round(); - - execute_shplonk_batched_quotient_round(); - - execute_shplonk_partial_evaluation_round(); - - execute_final_pcs_round(); + execute_zeromorph_rounds(); execute_transcript_consistency_univariate_opening_round(); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index 3d8aeead828..c4b895ecf88 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -1,6 +1,5 @@ #pragma once -#include "barretenberg/commitment_schemes/gemini/gemini.hpp" -#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/flavor/ecc_vm.hpp" #include "barretenberg/goblin/translation_evaluations.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" @@ -24,6 +23,7 @@ template class ECCVMProver_ { using Curve = typename Flavor::Curve; using Transcript = typename Flavor::Transcript; using TranslationEvaluations = bb::TranslationEvaluations; + using ZeroMorph = ZeroMorphProver_; public: explicit ECCVMProver_(const std::shared_ptr& input_key, @@ -35,11 +35,7 @@ template class ECCVMProver_ { BB_PROFILE void execute_log_derivative_commitments_round(); BB_PROFILE void execute_grand_product_computation_round(); BB_PROFILE void execute_relation_check_rounds(); - BB_PROFILE void execute_univariatization_round(); - BB_PROFILE void execute_pcs_evaluation_round(); - BB_PROFILE void execute_shplonk_batched_quotient_round(); - BB_PROFILE void execute_shplonk_partial_evaluation_round(); - BB_PROFILE void execute_final_pcs_round(); + BB_PROFILE void execute_zeromorph_rounds(); BB_PROFILE void execute_transcript_consistency_univariate_opening_round(); HonkProof& export_proof(); @@ -72,13 +68,8 @@ template class ECCVMProver_ { FF translation_batching_challenge_v; // to be rederived by the translator verifier SumcheckOutput sumcheck_output; - GeminiProverOutput gemini_output; - ShplonkProverOutput shplonk_output; std::shared_ptr commitment_key; - using Gemini = GeminiProver_; - using Shplonk = ShplonkProver_; - private: HonkProof proof; }; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index d7f41fd4424..8b81dcf874e 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -31,11 +31,11 @@ template class ECCVMTranscriptTests : public ::testing::Test { * * @return TranscriptManifest */ - TranscriptManifest construct_eccvm_honk_manifest(size_t circuit_size, size_t ipa_poly_degree) + TranscriptManifest construct_eccvm_honk_manifest(size_t circuit_size, size_t log_ipa_poly_degree) { TranscriptManifest manifest_expected; - auto log_n = numeric::get_msb(circuit_size); + ASSERT(log_n == log_ipa_poly_degree); size_t MAX_PARTIAL_RELATION_LENGTH = Flavor::BATCHED_RELATION_PARTIAL_LENGTH; // Size of types is number of bb::frs needed to represent the type @@ -147,31 +147,50 @@ template class ECCVMTranscriptTests : public ::testing::Test { manifest_expected.add_challenge(round, "rho"); round++; - for (size_t i = 1; i < log_n; ++i) { + for (size_t i = 0; i < log_n; ++i) { std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:FOLD_" + idx, frs_per_G); + manifest_expected.add_entry(round, "ZM:C_q_" + idx, frs_per_G); } - manifest_expected.add_challenge(round, "Gemini:r"); + manifest_expected.add_challenge(round, "ZM:y"); round++; + manifest_expected.add_entry(round, "ZM:C_q", frs_per_G); + manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); + + round++; + manifest_expected.add_entry(round, "IPA:poly_degree_plus_1", frs_per_uint32); + manifest_expected.add_challenge(round, "IPA:generator_challenge"); + for (size_t i = 0; i < log_n; ++i) { - std::string idx = std::to_string(i); - manifest_expected.add_entry(round, "Gemini:a_" + idx, frs_per_Fr); + round++; + std::string idx = std::to_string(log_n - i - 1); + manifest_expected.add_entry(round, "IPA:L_" + idx, frs_per_G); + manifest_expected.add_entry(round, "IPA:R_" + idx, frs_per_G); + std::string label = "IPA:round_challenge_" + idx; + manifest_expected.add_challenge(round, label); } - manifest_expected.add_challenge(round, "Shplonk:nu"); round++; - manifest_expected.add_entry(round, "Shplonk:Q", frs_per_G); - manifest_expected.add_challenge(round, "Shplonk:z"); + manifest_expected.add_entry(round, "IPA:a_0", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:hack_commitment", frs_per_G); + manifest_expected.add_challenge(round, "Translation:evaluation_challenge_x"); + + round++; + manifest_expected.add_entry(round, "Translation:op", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:Px", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:Py", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:z1", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:z2", frs_per_Fr); + manifest_expected.add_entry(round, "Translation:hack_evaluation", frs_per_Fr); + manifest_expected.add_challenge(round, "Translation:ipa_batching_challenge"); round++; - manifest_expected.add_entry(round, "IPA:poly_degree", frs_per_uint32); + manifest_expected.add_entry(round, "IPA:poly_degree_plus_1", frs_per_uint32); manifest_expected.add_challenge(round, "IPA:generator_challenge"); - auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); - for (size_t i = 0; i < log_poly_degree; ++i) { + for (size_t i = 0; i < log_n; ++i) { round++; - std::string idx = std::to_string(i); + std::string idx = std::to_string(log_n - i - 1); manifest_expected.add_entry(round, "IPA:L_" + idx, frs_per_G); manifest_expected.add_entry(round, "IPA:R_" + idx, frs_per_G); std::string label = "IPA:round_challenge_" + idx; @@ -180,6 +199,7 @@ template class ECCVMTranscriptTests : public ::testing::Test { round++; manifest_expected.add_entry(round, "IPA:a_0", frs_per_Fr); + manifest_expected.add_challenge(round, "Translation:batching_challenge"); return manifest_expected; } @@ -227,8 +247,6 @@ TYPED_TEST_SUITE(ECCVMTranscriptTests, FlavorTypes); */ TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) { - GTEST_SKIP() << "TODO(https://github.com/AztecProtocol/barretenberg/issues/782): update and reinstate after the " - "protocol is finalized."; using Flavor = TypeParam; // Construct a simple circuit @@ -241,9 +259,8 @@ TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) // Check that the prover generated manifest agrees with the manifest hard coded in this suite auto manifest_expected = - this->construct_eccvm_honk_manifest(prover.key->circuit_size, prover.shplonk_output.witness.size()); + this->construct_eccvm_honk_manifest(prover.key->circuit_size, prover.sumcheck_output.challenge.size()); auto prover_manifest = prover.transcript->get_manifest(); - // Note: a manifest can be printed using manifest.print() for (size_t round = 0; round < manifest_expected.size(); ++round) { ASSERT_EQ(prover_manifest[round], manifest_expected[round]) << "Prover manifest discrepency in round " << round; @@ -257,9 +274,6 @@ TYPED_TEST(ECCVMTranscriptTests, ProverManifestConsistency) */ TYPED_TEST(ECCVMTranscriptTests, VerifierManifestConsistency) { - GTEST_SKIP() << "TODO(https://github.com/AztecProtocol/barretenberg/issues/782): update and reinstate after the " - "protocol is finalized."; - using Flavor = TypeParam; // Construct a simple circuit @@ -279,7 +293,10 @@ TYPED_TEST(ECCVMTranscriptTests, VerifierManifestConsistency) auto verifier_manifest = verifier.transcript->get_manifest(); // Note: a manifest can be printed using manifest.print() - for (size_t round = 0; round < prover_manifest.size(); ++round) { + // The last challenge generated by the ECCVM Prover is the translation univariate batching challenge and, on the + // verifier side, is only generated in the translator verifier hence the ECCVM prover's manifest will have one extra + // challenge + for (size_t round = 0; round < prover_manifest.size() - 1; ++round) { ASSERT_EQ(prover_manifest[round], verifier_manifest[round]) << "Prover/Verifier manifest discrepency in round " << round; } @@ -313,9 +330,6 @@ TYPED_TEST(ECCVMTranscriptTests, ChallengeGenerationTest) TYPED_TEST(ECCVMTranscriptTests, StructureTest) { - GTEST_SKIP() << "TODO(https://github.com/AztecProtocol/barretenberg/issues/782): update and reinstate after the " - "protocol is finalized."; - using Flavor = TypeParam; // Construct a simple circuit @@ -331,16 +345,17 @@ TYPED_TEST(ECCVMTranscriptTests, StructureTest) // try deserializing and serializing with no changes and check proof is still valid prover.transcript->deserialize_full_transcript(); prover.transcript->serialize_full_transcript(); - EXPECT_TRUE(verifier.verify_proof(prover.export_proof())); // we have changed nothing so proof is still valid + EXPECT_TRUE( + verifier.verify_proof(prover.transcript->proof_data)); // we have changed nothing so proof is still valid typename Flavor::Commitment one_group_val = Flavor::Commitment::one(); auto rand_val = Flavor::FF::random_element(); prover.transcript->transcript_Px_comm = one_group_val * rand_val; // choose random object to modify EXPECT_TRUE(verifier.verify_proof( - prover.export_proof())); // we have not serialized it back to the proof so it should still be fine + prover.transcript->proof_data)); // we have not serialized it back to the proof so it should still be fine prover.transcript->serialize_full_transcript(); - EXPECT_FALSE(verifier.verify_proof(prover.export_proof())); // the proof is now wrong after serializing it + EXPECT_FALSE(verifier.verify_proof(prover.transcript->proof_data)); // the proof is now wrong after serializing it prover.transcript->deserialize_full_transcript(); EXPECT_EQ(static_cast(prover.transcript->transcript_Px_comm), diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 71ce6e2ae6a..8db713a1034 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -1,6 +1,5 @@ #include "./eccvm_verifier.hpp" -#include "barretenberg/commitment_schemes/gemini/gemini.hpp" -#include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" +#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -32,15 +31,13 @@ template ECCVMVerifier_& ECCVMVerifier_::opera template bool ECCVMVerifier_::verify_proof(const HonkProof& proof) { using FF = typename Flavor::FF; - using GroupElement = typename Flavor::GroupElement; using Commitment = typename Flavor::Commitment; using PCS = typename Flavor::PCS; - using Curve = typename Flavor::Curve; - using Gemini = GeminiVerifier_; - using Shplonk = ShplonkVerifier_; + using ZeroMorph = ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; using Transcript = typename Flavor::Transcript; + using Curve = typename Flavor::Curve; RelationParameters relation_parameters; @@ -161,7 +158,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } - auto [multivariate_challenge, purported_evaluations, sumcheck_verified] = + auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, alpha, gate_challenges); // If Sumcheck did not verify, return false @@ -169,69 +166,13 @@ template bool ECCVMVerifier_::verify_proof(const HonkP return false; } - // Execute Gemini/Shplonk verification: - - // Construct inputs for Gemini verifier: - // - Multivariate opening point u = (u_0, ..., u_{d-1}) - // - batched unshifted and to-be-shifted polynomial commitments - auto batched_commitment_unshifted = GroupElement::zero(); - auto batched_commitment_to_be_shifted = GroupElement::zero(); - const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; - // Compute powers of batching challenge rho - FF rho = transcript->template get_challenge("rho"); - std::vector rhos = gemini::powers_of_rho(rho, NUM_POLYNOMIALS); - - // Compute batched multivariate evaluation - FF batched_evaluation = FF::zero(); - size_t evaluation_idx = 0; - for (auto& value : purported_evaluations.get_unshifted()) { - batched_evaluation += value * rhos[evaluation_idx]; - ++evaluation_idx; - } - for (auto& value : purported_evaluations.get_shifted()) { - batched_evaluation += value * rhos[evaluation_idx]; - ++evaluation_idx; - } - - // Construct batched commitment for NON-shifted polynomials - size_t commitment_idx = 0; - for (auto& commitment : commitments.get_unshifted()) { - // TODO(@zac-williamson)(https://github.com/AztecProtocol/barretenberg/issues/820) ensure ECCVM polynomial - // commitments are never points at infinity - if (commitment.y != 0) { - batched_commitment_unshifted += commitment * rhos[commitment_idx]; - } else { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/820) - } - ++commitment_idx; - } - - // Construct batched commitment for to-be-shifted polynomials - for (auto& commitment : commitments.get_to_be_shifted()) { - // TODO(@zac-williamson) ensure ECCVM polynomial commitments are never points at infinity (#2214) - if (commitment.y != 0) { - batched_commitment_to_be_shifted += commitment * rhos[commitment_idx]; - } else { - // TODO(https://github.com/AztecProtocol/barretenberg/issues/820) - } - ++commitment_idx; - } - - // Produce a Gemini claim consisting of: - // - d+1 commitments [Fold_{r}^(0)], [Fold_{-r}^(0)], and [Fold^(l)], l = 1:d-1 - // - d+1 evaluations a_0_pos, and a_l, l = 0:d-1 - auto gemini_claim = Gemini::reduce_verification(multivariate_challenge, - batched_evaluation, - batched_commitment_unshifted, - batched_commitment_to_be_shifted, - transcript); - - // Produce a Shplonk claim: commitment [Q] - [Q_z], evaluation zero (at random challenge z) - auto shplonk_claim = Shplonk::reduce_verification(pcs_verification_key, gemini_claim, transcript); - - // Verify the Shplonk claim with KZG or IPA - auto multivariate_opening_verified = PCS::verify(pcs_verification_key, shplonk_claim, transcript); - + bool multivariate_opening_verified = ZeroMorph::verify(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + claimed_evaluations.get_unshifted(), + claimed_evaluations.get_shifted(), + multivariate_challenge, + pcs_verification_key, + transcript); // Execute transcript consistency univariate opening round // TODO(#768): Find a better way to do this. See issue for details. bool univariate_opening_verified = false; @@ -271,7 +212,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP // Construct and verify batched opening claim OpeningClaim batched_univariate_claim = { { evaluation_challenge_x, batched_transcript_eval }, batched_commitment }; - univariate_opening_verified = PCS::verify(pcs_verification_key, batched_univariate_claim, transcript); + univariate_opening_verified = PCS::reduce_verify(pcs_verification_key, batched_univariate_claim, transcript); } return sumcheck_verified.value() && multivariate_opening_verified && univariate_opening_verified; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp index 72f62b589fe..aa77a8d1030 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp @@ -599,15 +599,23 @@ template class ECCVMBa Commitment lookup_inverses_comm; std::vector> sumcheck_univariates; std::array sumcheck_evaluations; - std::vector gemini_univariate_comms; - std::vector gemini_a_evals; - Commitment shplonk_q_comm; - Commitment kzg_w_comm; - // the rest are only for Grumpkin + std::vector zm_cq_comms; + Commitment zm_cq_comm; uint32_t ipa_poly_degree; std::vector ipa_l_comms; std::vector ipa_r_comms; FF ipa_a_0_eval; + Commitment translation_hack_comm; + FF translation_eval_op; + FF translation_eval_px; + FF translation_eval_py; + FF translation_eval_z1; + FF translation_eval_z2; + FF hack_eval; + uint32_t translation_ipa_poly_degree; + std::vector translation_ipa_l_comms; + std::vector translation_ipa_r_comms; + FF translation_ipa_a_0_eval; Transcript() = default; @@ -781,43 +789,60 @@ template class ECCVMBa } sumcheck_evaluations = NativeTranscript::template deserialize_from_buffer>( NativeTranscript::proof_data, num_frs_read); - for (size_t i = 0; i < log_n - 1; ++i) { - gemini_univariate_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read)); - } for (size_t i = 0; i < log_n; ++i) { - gemini_a_evals.emplace_back( - NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read)); + zm_cq_comms.push_back( + NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read)); + } + zm_cq_comm = NativeTranscript::template deserialize_from_buffer(proof_data, num_frs_read); + + ipa_poly_degree = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + ipa_l_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); + ipa_r_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); } - shplonk_q_comm = NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read); - if (std::is_same>::value) { - kzg_w_comm = NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read); - } else if (std::is_same>::value) { - ipa_poly_degree = NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read); - auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); - for (size_t i = 0; i < log_poly_degree; ++i) { - ipa_l_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read)); - ipa_r_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( - NativeTranscript::proof_data, num_frs_read)); - } - ipa_a_0_eval = - NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); - } else { - throw_or_abort("Unsupported PCS"); + ipa_a_0_eval = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_hack_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + translation_eval_op = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_px = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_py = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_z1 = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + translation_eval_z2 = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + hack_eval = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); + + translation_ipa_poly_degree = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + + for (size_t i = 0; i < log_poly_degree; ++i) { + translation_ipa_l_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); + translation_ipa_r_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); } + + translation_ipa_a_0_eval = + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); } void serialize_full_transcript() { size_t old_proof_length = NativeTranscript::proof_data.size(); NativeTranscript::proof_data.clear(); - size_t log_n = numeric::get_msb(circuit_size); NativeTranscript::template serialize_to_buffer(circuit_size, NativeTranscript::proof_data); + size_t log_n = numeric::get_msb(circuit_size); + NativeTranscript::template serialize_to_buffer(transcript_add_comm, NativeTranscript::proof_data); NativeTranscript::template serialize_to_buffer(transcript_mul_comm, NativeTranscript::proof_data); NativeTranscript::template serialize_to_buffer(transcript_eq_comm, NativeTranscript::proof_data); @@ -903,26 +928,39 @@ template class ECCVMBa NativeTranscript::template serialize_to_buffer(sumcheck_univariates[i], NativeTranscript::proof_data); } NativeTranscript::template serialize_to_buffer(sumcheck_evaluations, NativeTranscript::proof_data); - for (size_t i = 0; i < log_n - 1; ++i) { - NativeTranscript::template serialize_to_buffer(gemini_univariate_comms[i], - NativeTranscript::proof_data); - } for (size_t i = 0; i < log_n; ++i) { - NativeTranscript::template serialize_to_buffer(gemini_a_evals[i], NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(zm_cq_comms[i], NativeTranscript::proof_data); } - NativeTranscript::template serialize_to_buffer(shplonk_q_comm, NativeTranscript::proof_data); - if (std::is_same>::value) { - NativeTranscript::template serialize_to_buffer(kzg_w_comm, NativeTranscript::proof_data); - } else if (std::is_same>::value) { - NativeTranscript::template serialize_to_buffer(ipa_poly_degree, NativeTranscript::proof_data); - auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); - for (size_t i = 0; i < log_poly_degree; ++i) { - NativeTranscript::template serialize_to_buffer(ipa_l_comms[i], NativeTranscript::proof_data); - NativeTranscript::template serialize_to_buffer(ipa_r_comms[i], NativeTranscript::proof_data); - } - - NativeTranscript::template serialize_to_buffer(ipa_a_0_eval, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(zm_cq_comm, NativeTranscript::proof_data); + + NativeTranscript::template serialize_to_buffer(ipa_poly_degree, NativeTranscript::proof_data); + + auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + NativeTranscript::template serialize_to_buffer(ipa_l_comms[i], NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(ipa_r_comms[i], NativeTranscript::proof_data); } + + NativeTranscript::template serialize_to_buffer(ipa_a_0_eval, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_hack_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_op, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_px, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_py, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_z1, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_eval_z2, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(hack_eval, NativeTranscript::proof_data); + + NativeTranscript::template serialize_to_buffer(translation_ipa_poly_degree, NativeTranscript::proof_data); + log_poly_degree = static_cast(numeric::get_msb(translation_ipa_poly_degree)); + for (size_t i = 0; i < log_poly_degree; ++i) { + NativeTranscript::template serialize_to_buffer(translation_ipa_l_comms[i], + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(translation_ipa_r_comms[i], + NativeTranscript::proof_data); + } + + serialize_to_buffer(translation_ipa_a_0_eval, proof_data); + ASSERT(NativeTranscript::proof_data.size() == old_proof_length); } }; diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index e4a033ece45..7f48253dffc 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -502,7 +502,7 @@ class GoblinUltraFlavor { std::array sumcheck_evaluations; std::vector zm_cq_comms; Commitment zm_cq_comm; - Commitment zm_pi_comm; + Commitment kzg_w_comm; Transcript_() = default; @@ -561,7 +561,7 @@ class GoblinUltraFlavor { zm_cq_comms.push_back(deserialize_from_buffer(proof_data, num_frs_read)); } zm_cq_comm = deserialize_from_buffer(proof_data, num_frs_read); - zm_pi_comm = deserialize_from_buffer(proof_data, num_frs_read); + kzg_w_comm = deserialize_from_buffer(proof_data, num_frs_read); } void serialize_full_transcript() @@ -597,7 +597,7 @@ class GoblinUltraFlavor { serialize_to_buffer(zm_cq_comms[i], proof_data); } serialize_to_buffer(zm_cq_comm, proof_data); - serialize_to_buffer(zm_pi_comm, proof_data); + serialize_to_buffer(kzg_w_comm, proof_data); ASSERT(proof_data.size() == old_proof_length); } diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index a2323eba35f..f807449ba57 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -474,7 +474,7 @@ class UltraFlavor { std::array sumcheck_evaluations; std::vector zm_cq_comms; Commitment zm_cq_comm; - Commitment zm_pi_comm; + Commitment kzg_w_comm; Transcript() = default; @@ -532,7 +532,7 @@ class UltraFlavor { zm_cq_comms.push_back(deserialize_from_buffer(proof_data, num_frs_read)); } zm_cq_comm = deserialize_from_buffer(proof_data, num_frs_read); - zm_pi_comm = deserialize_from_buffer(proof_data, num_frs_read); + kzg_w_comm = deserialize_from_buffer(proof_data, num_frs_read); } /** * @brief Serializes the structure variables into a FULL Ultra proof. Should be called only if @@ -565,7 +565,7 @@ class UltraFlavor { serialize_to_buffer(zm_cq_comms[i], proof_data); } serialize_to_buffer(zm_cq_comm, proof_data); - serialize_to_buffer(zm_pi_comm, proof_data); + serialize_to_buffer(kzg_w_comm, proof_data); // sanity check to make sure we generate the same length of proof as before. ASSERT(proof_data.size() == old_proof_length); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index 88905126d27..e217028e27b 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -55,8 +55,7 @@ template bool DeciderVerifier_::verify_proof(const Hon multivariate_challenge, transcript); - auto verified = - accumulator->verification_key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return sumcheck_verified.value() && verified; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp index 37138a4bfef..bf457cf0e18 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp @@ -116,13 +116,13 @@ std::array UltraRecursiveVerifier_::ve auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, alpha, gate_challenges); // Execute ZeroMorph multilinear PCS evaluation verifier - auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), - commitments.get_to_be_shifted(), - claimed_evaluations.get_unshifted(), - claimed_evaluations.get_shifted(), - multivariate_challenge, - transcript); - return pairing_points; + auto verifier_accumulator = ZeroMorph::verify(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + claimed_evaluations.get_unshifted(), + claimed_evaluations.get_shifted(), + multivariate_challenge, + transcript); + return verifier_accumulator; } template class UltraRecursiveVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp index 6cb2a9653d4..39288e665f4 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp @@ -244,7 +244,6 @@ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { - info("sumcheck failed"); return false; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 9ce6bada482..18e30a1cdaf 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -75,8 +75,8 @@ template bool MergeVerifier_::verify_proof(const HonkP OpeningClaim batched_claim = { { kappa, batched_eval }, batched_commitment }; - auto verified = PCS::verify(pcs_verification_key, batched_claim, transcript); - + auto pairing_points = PCS::reduce_verify(batched_claim, transcript); + auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return identity_checked && verified; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 6b20e56daa4..15f21c9ca74 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -76,18 +76,17 @@ template bool UltraVerifier_::verify_proof(const HonkP return false; } - // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the - // unrolled protocol. + // Execute ZeroMorph rounds and check the pcs verifier accumulator returned. See + // https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the unrolled protocol. auto pairing_points = ZeroMorph::verify(commitments.get_unshifted(), commitments.get_to_be_shifted(), claimed_evaluations.get_unshifted(), claimed_evaluations.get_shifted(), multivariate_challenge, transcript); - - auto verified = key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); - - return sumcheck_verified.value() && verified; + auto pcs_verified = key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + return sumcheck_verified.value() && pcs_verified; + ; } template class UltraVerifier_; From ece6d82858772cbe41e5494357c9da0e039d4faa Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 21 Mar 2024 19:39:27 -0300 Subject: [PATCH 14/36] chore: Remove unused FunctionLeafPreimage struct (#5354) No longer used after the new contract deployment flow. --- .../function_leaf_preimage.test.ts.snap | 3 - .../structs/function_leaf_preimage.test.ts | 35 -------- .../src/structs/function_leaf_preimage.ts | 80 ------------------- yarn-project/circuits.js/src/structs/index.ts | 1 - 4 files changed, 119 deletions(-) delete mode 100644 yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap delete mode 100644 yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts delete mode 100644 yarn-project/circuits.js/src/structs/function_leaf_preimage.ts diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap deleted file mode 100644 index d6d47cb4160..00000000000 --- a/yarn-project/circuits.js/src/structs/__snapshots__/function_leaf_preimage.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FunctionLeafPreimage computes a function leaf 1`] = `Fr<0x1f2e3193c7187347a099ee7cb5d6ac077da6b18706fe5508e658a3d0a05494f7>`; diff --git a/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts b/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts deleted file mode 100644 index 1a41faa900e..00000000000 --- a/yarn-project/circuits.js/src/structs/function_leaf_preimage.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { FunctionSelector } from '@aztec/foundation/abi'; -import { Fr } from '@aztec/foundation/fields'; -import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; - -import { FUNCTION_LEAF_PREIMAGE_LENGTH } from '../constants.gen.js'; -import { FunctionLeafPreimage } from './function_leaf_preimage.js'; - -describe('FunctionLeafPreimage', () => { - let leaf: FunctionLeafPreimage; - - beforeAll(() => { - setupCustomSnapshotSerializers(expect); - leaf = new FunctionLeafPreimage(new FunctionSelector(8972), false, true, Fr.ZERO, Fr.ZERO); - }); - - it(`serializes to buffer and deserializes it back`, () => { - const buffer = leaf.toBuffer(); - const res = FunctionLeafPreimage.fromBuffer(buffer); - expect(res).toEqual(leaf); - }); - - it('number of fields matches constant', () => { - const fields = leaf.toFields(); - expect(fields.length).toBe(FUNCTION_LEAF_PREIMAGE_LENGTH); - }); - - it('computes a function leaf', () => { - const emptyLeaf = new FunctionLeafPreimage(new FunctionSelector(0), false, false, Fr.ZERO, Fr.ZERO); - const hash = emptyLeaf.hash(); - expect(hash).toMatchSnapshot(); - - // Value used in empty_hash test in function_leaf_preimage.nr - // console.log("hash", hash.toString()); - }); -}); diff --git a/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts b/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts deleted file mode 100644 index 6a5b0f22cc8..00000000000 --- a/yarn-project/circuits.js/src/structs/function_leaf_preimage.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { FunctionSelector } from '@aztec/foundation/abi'; -import { pedersenHash } from '@aztec/foundation/crypto'; -import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; -import { FieldsOf } from '@aztec/foundation/types'; - -import { FUNCTION_LEAF_PREIMAGE_LENGTH, GeneratorIndex } from '../constants.gen.js'; - -/** - * A class representing the "preimage" of a function tree leaf. - */ -export class FunctionLeafPreimage { - constructor( - /** - * Function selector. - */ - public functionSelector: FunctionSelector, - /** - * Indicates whether the function is only callable by self or not. - */ - public isInternal: boolean, - /** - * Indicates whether the function is private or public. - */ - public isPrivate: boolean, - /** - * Verification key hash of the function. - */ - public vkHash: Fr, - /** - * Hash of the ACIR of the function. - */ - public acirHash: Fr, - ) {} - - static getFields(fields: FieldsOf) { - return [fields.functionSelector, fields.isInternal, fields.isPrivate, fields.vkHash, fields.acirHash] as const; - } - - /** - * Serialize this as a buffer. - * @returns The buffer. - */ - toBuffer(): Buffer { - return serializeToBuffer(...FunctionLeafPreimage.getFields(this)); - } - - toFields(): Fr[] { - const fields = serializeToFields(...FunctionLeafPreimage.getFields(this)); - if (fields.length !== FUNCTION_LEAF_PREIMAGE_LENGTH) { - throw new Error( - `Invalid number of fields for FunctionLeafPreimage. Expected ${FUNCTION_LEAF_PREIMAGE_LENGTH}, got ${fields.length}`, - ); - } - return fields; - } - - /** - * Deserializes from a buffer or reader, corresponding to a write in cpp. - * @param buffer - Buffer or reader to read from. - * @returns A new instance of FunctionLeafPreimage. - */ - static fromBuffer(buffer: Buffer | BufferReader): FunctionLeafPreimage { - const reader = BufferReader.asReader(buffer); - return new FunctionLeafPreimage( - reader.readObject(FunctionSelector), - reader.readBoolean(), - reader.readBoolean(), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), - ); - } - - hash(): Fr { - return pedersenHash( - this.toFields().map(field => field.toBuffer()), - GeneratorIndex.FUNCTION_LEAF, - ); - } -} diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index b4a4370350d..ab67442f937 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -7,7 +7,6 @@ export * from './content_commitment.js'; export * from './contract_storage_read.js'; export * from './contract_storage_update_request.js'; export * from './function_data.js'; -export * from './function_leaf_preimage.js'; export * from './global_variables.js'; export * from './header.js'; export * from './kernel/combined_accumulated_data.js'; From 0ef736756257910b0c36cb8c1bfaf0fd83d53236 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 21 Mar 2024 20:14:54 -0300 Subject: [PATCH 15/36] fix: Generate noir interface for constructors (#5352) With the last changes for contract deployment, a contract **can** call another contract's initializer. Co-authored-by: ludamad --- .../noir-compiler/src/contract-interface-gen/noir.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts b/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts index f76174c0732..eabae4c11a1 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/noir.ts @@ -279,10 +279,8 @@ ${contractImpl} * @returns The corresponding ts code. */ export function generateNoirContractInterface(artifact: ContractArtifact) { - // We don't allow calling a constructor, internal fns, or unconstrained fns from other contracts - const methods = artifact.functions.filter( - f => f.name !== 'constructor' && !f.isInternal && f.functionType !== FunctionType.UNCONSTRAINED, - ); + // We don't allow calling internal fns or unconstrained fns from other contracts + const methods = artifact.functions.filter(f => !f.isInternal && f.functionType !== FunctionType.UNCONSTRAINED); const paramStructs = methods.flatMap(m => collectStructs(m.parameters, [m.name])).map(generateStruct); const privateContractStruct = generateContractStruct(artifact.name, 'private', methods); const publicContractStruct = generateContractStruct(artifact.name, 'public', methods); From 5d1a47812d6172c6061761348634af510e4e32f7 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Thu, 21 Mar 2024 16:48:58 -0700 Subject: [PATCH 16/36] chore: Name change: gen perm sort to delta range constraint (#5378) Change the naming convention "gen perm sort" to "delta range constraint". The name GenPermSort is misleading. The relation actually is checking that the difference (delta) between wire values is no more than 3. The original name stems from the context in which this relation is used but says nothing about the actual constraint being applied. Closes https://github.com/AztecProtocol/barretenberg/issues/919 --- .../relations_bench/relations.bench.cpp | 4 +- .../circuit_checker/ultra_circuit_checker.cpp | 6 +-- .../circuit_checker/ultra_circuit_checker.hpp | 4 +- .../barretenberg/flavor/goblin_translator.hpp | 24 +++++----- .../src/barretenberg/flavor/goblin_ultra.hpp | 12 ++--- .../flavor/goblin_ultra_recursive.hpp | 2 +- .../cpp/src/barretenberg/flavor/ultra.hpp | 18 +++---- .../barretenberg/flavor/ultra_recursive.hpp | 20 ++++---- .../honk/proof_system/permutation_library.hpp | 5 +- .../arithmetization/arithmetization.hpp | 9 ++-- .../goblin_ultra_circuit_builder.cpp | 10 ++-- .../circuit_builder/ultra_circuit_builder.cpp | 48 +++++++++---------- .../protogalaxy/combiner.test.cpp | 4 +- .../protogalaxy/combiner_example_gen.py | 2 +- ...pp => delta_range_constraint_relation.hpp} | 16 +++---- ...n_translator_relation_consistency.test.cpp | 4 +- ...lator_delta_range_constraint_relation.cpp} | 14 +++--- ...lator_delta_range_constraint_relation.hpp} | 4 +- .../ultra_relation_consistency.test.cpp | 18 +++---- .../barretenberg/sumcheck/sumcheck.test.cpp | 2 +- .../ultra_honk/relation_correctness.test.cpp | 20 ++++---- .../barretenberg/ultra_honk/sumcheck.test.cpp | 2 +- 22 files changed, 125 insertions(+), 123 deletions(-) rename barretenberg/cpp/src/barretenberg/relations/{gen_perm_sort_relation.hpp => delta_range_constraint_relation.hpp} (87%) rename barretenberg/cpp/src/barretenberg/relations/translator_vm/{translator_gen_perm_sort_relation.cpp => translator_delta_range_constraint_relation.cpp} (89%) rename barretenberg/cpp/src/barretenberg/relations/translator_vm/{translator_gen_perm_sort_relation.hpp => translator_delta_range_constraint_relation.hpp} (91%) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/relations_bench/relations.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/relations_bench/relations.bench.cpp index 45d2c1acbe2..49a77736219 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/relations_bench/relations.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/relations_bench/relations.bench.cpp @@ -32,7 +32,7 @@ template void execute_relation(::benchmark: } } BENCHMARK(execute_relation>); -BENCHMARK(execute_relation>); +BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); @@ -43,7 +43,7 @@ BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); -BENCHMARK(execute_relation>); +BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); BENCHMARK(execute_relation>); diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp index 1a31f3355ba..3747c8063a6 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp @@ -90,9 +90,9 @@ bool UltraCircuitChecker::check_block(Builder& builder, info("Failed Auxiliary relation at row idx = ", idx); return false; } - result = result && check_relation(values, params); + result = result && check_relation(values, params); if (result == false) { - info("Failed GenPermSort relation at row idx = ", idx); + info("Failed DeltaRangeConstraint relation at row idx = ", idx); return false; } result = result && check_lookup(values, lookup_hash_table); @@ -234,7 +234,7 @@ void UltraCircuitChecker::populate_values( values.q_o = block.q_3()[idx]; values.q_4 = block.q_4()[idx]; values.q_arith = block.q_arith()[idx]; - values.q_sort = block.q_sort()[idx]; + values.q_delta_range = block.q_delta_range()[idx]; values.q_elliptic = block.q_elliptic()[idx]; values.q_aux = block.q_aux()[idx]; values.q_lookup = block.q_lookup_type()[idx]; diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp index 2a5680b001b..5aea34513b6 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp @@ -3,9 +3,9 @@ #include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/ecc_op_queue_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/poseidon2_external_relation.hpp" #include "barretenberg/relations/poseidon2_internal_relation.hpp" #include "barretenberg/relations/relation_parameters.hpp" @@ -21,7 +21,7 @@ class UltraCircuitChecker { using Arithmetic = UltraArithmeticRelation; using Elliptic = EllipticRelation; using Auxiliary = AuxiliaryRelation; - using GenPermSort = GenPermSortRelation; + using DeltaRangeConstraint = DeltaRangeConstraintRelation; using PoseidonExternal = Poseidon2ExternalRelation; using PoseidonInternal = Poseidon2InternalRelation; using Params = RelationParameters; diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp index f69a5814155..211171f0087 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp @@ -11,8 +11,8 @@ #include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/relations/translator_vm/translator_decomposition_relation.hpp" +#include "barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp" #include "barretenberg/relations/translator_vm/translator_extra_relations.hpp" -#include "barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.hpp" #include "barretenberg/relations/translator_vm/translator_non_native_field_relation.hpp" #include "barretenberg/relations/translator_vm/translator_permutation_relation.hpp" #include "relation_definitions.hpp" @@ -38,7 +38,7 @@ class GoblinTranslatorFlavor { static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 2048; // The size of the circuit which is filled with non-zero values for most polynomials. Most relations (everything - // except for Permutation and GenPermSort) can be evaluated just on the first chunk + // except for Permutation and DeltaRangeConstraint) can be evaluated just on the first chunk // It is also the only parameter that can be changed without updating relations or structures in the flavor static constexpr size_t MINI_CIRCUIT_SIZE = mini_circuit_size; @@ -56,7 +56,7 @@ class GoblinTranslatorFlavor { // Number of wires static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES; - // The step in the GenPermSort relation + // The step in the DeltaRangeConstraint relation static constexpr size_t SORT_STEP = 3; // The bitness of the range constraint @@ -82,7 +82,7 @@ class GoblinTranslatorFlavor { using GrandProductRelations = std::tuple>; // define the tuple of Relations that comprise the Sumcheck relation using Relations = std::tuple, - GoblinTranslatorGenPermSortRelation, + GoblinTranslatorDeltaRangeConstraintRelation, GoblinTranslatorOpcodeConstraintRelation, GoblinTranslatorAccumulatorTransferRelation, GoblinTranslatorDecompositionRelation, @@ -99,13 +99,13 @@ class GoblinTranslatorFlavor { static constexpr size_t NUM_RELATIONS = std::tuple_size_v; // define the containers for storing the contributions from each relation in Sumcheck - using SumcheckTupleOfTuplesOfUnivariates = - std::tuple::SumcheckTupleOfUnivariatesOverSubrelations, - typename GoblinTranslatorGenPermSortRelation::SumcheckTupleOfUnivariatesOverSubrelations, - typename GoblinTranslatorOpcodeConstraintRelation::SumcheckTupleOfUnivariatesOverSubrelations, - typename GoblinTranslatorAccumulatorTransferRelation::SumcheckTupleOfUnivariatesOverSubrelations, - typename GoblinTranslatorDecompositionRelation::SumcheckTupleOfUnivariatesOverSubrelations, - typename GoblinTranslatorNonNativeFieldRelation::SumcheckTupleOfUnivariatesOverSubrelations>; + using SumcheckTupleOfTuplesOfUnivariates = std::tuple< + typename GoblinTranslatorPermutationRelation::SumcheckTupleOfUnivariatesOverSubrelations, + typename GoblinTranslatorDeltaRangeConstraintRelation::SumcheckTupleOfUnivariatesOverSubrelations, + typename GoblinTranslatorOpcodeConstraintRelation::SumcheckTupleOfUnivariatesOverSubrelations, + typename GoblinTranslatorAccumulatorTransferRelation::SumcheckTupleOfUnivariatesOverSubrelations, + typename GoblinTranslatorDecompositionRelation::SumcheckTupleOfUnivariatesOverSubrelations, + typename GoblinTranslatorNonNativeFieldRelation::SumcheckTupleOfUnivariatesOverSubrelations>; using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values()); private: @@ -157,7 +157,7 @@ class GoblinTranslatorFlavor { * @details Goblin proves that several polynomials contain only values in a certain range through 2 relations: * 1) A grand product which ignores positions of elements (GoblinTranslatorPermutationRelation) * 2) A relation enforcing a certain ordering on the elements of the given polynomial - * (GoblinTranslatorGenPermSortRelation) + * (GoblinTranslatorDeltaRangeConstraintRelation) * * We take the values from 4 polynomials, and spread them into 5 polynomials + add all the steps from MAX_VALUE * to 0. We order these polynomials and use them in the denominator of the grand product, at the same time diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 7f48253dffc..a8ed0ceb79f 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -8,9 +8,9 @@ #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" #include "barretenberg/relations/databus_lookup_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/ecc_op_queue_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/poseidon2_external_relation.hpp" @@ -53,7 +53,7 @@ class GoblinUltraFlavor { using Relations_ = std::tuple, bb::UltraPermutationRelation, bb::LookupRelation, - bb::GenPermSortRelation, + bb::DeltaRangeConstraintRelation, bb::EllipticRelation, bb::AuxiliaryRelation, bb::EccOpQueueRelation, @@ -103,7 +103,7 @@ class GoblinUltraFlavor { q_o, // column 4 q_4, // column 5 q_arith, // column 6 - q_sort, // column 7 + q_delta_range, // column 7 q_elliptic, // column 8 q_aux, // column 9 q_lookup, // column 10 @@ -139,7 +139,7 @@ class GoblinUltraFlavor { q_o, q_4, q_arith, - q_sort, + q_delta_range, q_elliptic, q_aux, q_lookup, @@ -386,7 +386,7 @@ class GoblinUltraFlavor { q_4 = "Q_4"; q_m = "Q_M"; q_arith = "Q_ARITH"; - q_sort = "Q_SORT"; + q_delta_range = "Q_SORT"; q_elliptic = "Q_ELLIPTIC"; q_aux = "Q_AUX"; q_lookup = "Q_LOOKUP"; @@ -427,7 +427,7 @@ class GoblinUltraFlavor { this->q_4 = verification_key->q_4; this->q_c = verification_key->q_c; this->q_arith = verification_key->q_arith; - this->q_sort = verification_key->q_sort; + this->q_delta_range = verification_key->q_delta_range; this->q_elliptic = verification_key->q_elliptic; this->q_aux = verification_key->q_aux; this->q_lookup = verification_key->q_lookup; diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 21b3f80dd0e..040439dc3c3 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -127,7 +127,7 @@ template class GoblinUltraRecursiveFlavor_ { this->q_4 = Commitment::from_witness(builder, native_key->q_4); this->q_c = Commitment::from_witness(builder, native_key->q_c); this->q_arith = Commitment::from_witness(builder, native_key->q_arith); - this->q_sort = Commitment::from_witness(builder, native_key->q_sort); + this->q_delta_range = Commitment::from_witness(builder, native_key->q_delta_range); this->q_elliptic = Commitment::from_witness(builder, native_key->q_elliptic); this->q_aux = Commitment::from_witness(builder, native_key->q_aux); this->q_lookup = Commitment::from_witness(builder, native_key->q_lookup); diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index f807449ba57..d6db5c90909 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -9,8 +9,8 @@ #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" @@ -46,7 +46,7 @@ class UltraFlavor { using Relations = std::tuple, bb::UltraPermutationRelation, bb::LookupRelation, - bb::GenPermSortRelation, + bb::DeltaRangeConstraintRelation, bb::EllipticRelation, bb::AuxiliaryRelation>; @@ -94,7 +94,7 @@ class UltraFlavor { q_o, // column 4 q_4, // column 5 q_arith, // column 6 - q_sort, // column 7 + q_delta_range, // column 7 q_elliptic, // column 8 q_aux, // column 9 q_lookup, // column 10 @@ -117,7 +117,7 @@ class UltraFlavor { auto get_selectors() { - return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, q_elliptic, q_aux, q_lookup }; + return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_delta_range, q_elliptic, q_aux, q_lookup }; }; auto get_sigma_polynomials() { return RefArray{ sigma_1, sigma_2, sigma_3, sigma_4 }; }; auto get_id_polynomials() { return RefArray{ id_1, id_2, id_3, id_4 }; }; @@ -187,7 +187,7 @@ class UltraFlavor { q_4, // column 4 q_m, // column 5 q_arith, // column 6 - q_sort, // column 7 + q_delta_range, // column 7 q_elliptic, // column 8 q_aux, // column 9 q_lookup, // column 10 @@ -228,7 +228,7 @@ class UltraFlavor { // Gemini-specific getters. auto get_unshifted() { - return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, + return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_delta_range, q_elliptic, q_aux, q_lookup, sigma_1, sigma_2, sigma_3, sigma_4, id_1, id_2, id_3, id_4, table_1, table_2, table_3, table_4, lagrange_first, lagrange_last, w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup @@ -238,7 +238,7 @@ class UltraFlavor { auto get_precomputed() { - return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, + return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_delta_range, q_elliptic, q_aux, q_lookup, sigma_1, sigma_2, sigma_3, sigma_4, id_1, id_2, id_3, id_4, table_1, table_2, table_3, table_4, lagrange_first, lagrange_last @@ -382,7 +382,7 @@ class UltraFlavor { q_4 = "Q_4"; q_m = "Q_M"; q_arith = "Q_ARITH"; - q_sort = "Q_SORT"; + q_delta_range = "Q_SORT"; q_elliptic = "Q_ELLIPTIC"; q_aux = "Q_AUX"; q_lookup = "Q_LOOKUP"; @@ -420,7 +420,7 @@ class UltraFlavor { q_o = verification_key->q_o; q_4 = verification_key->q_4; q_arith = verification_key->q_arith; - q_sort = verification_key->q_sort; + q_delta_range = verification_key->q_delta_range; q_elliptic = verification_key->q_elliptic; q_aux = verification_key->q_aux; q_lookup = verification_key->q_lookup; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index d1b4174252f..5f905863c4c 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -11,8 +11,8 @@ #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" @@ -74,7 +74,7 @@ template class UltraRecursiveFlavor_ { using Relations = std::tuple, bb::UltraPermutationRelation, bb::LookupRelation, - bb::GenPermSortRelation, + bb::DeltaRangeConstraintRelation, bb::EllipticRelation, bb::AuxiliaryRelation>; @@ -116,7 +116,7 @@ template class UltraRecursiveFlavor_ { q_o, // column 4 q_4, // column 5 q_arith, // column 6 - q_sort, // column 7 + q_delta_range, // column 7 q_elliptic, // column 8 q_aux, // column 9 q_lookup, // column 10 @@ -137,7 +137,7 @@ template class UltraRecursiveFlavor_ { auto get_selectors() { - return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, q_elliptic, q_aux, q_lookup }; + return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_delta_range, q_elliptic, q_aux, q_lookup }; }; auto get_sigma_polynomials() { return RefArray{ sigma_1, sigma_2, sigma_3, sigma_4 }; }; auto get_id_polynomials() { return RefArray{ id_1, id_2, id_3, id_4 }; }; @@ -190,7 +190,7 @@ template class UltraRecursiveFlavor_ { q_4, // column 4 q_m, // column 5 q_arith, // column 6 - q_sort, // column 7 + q_delta_range, // column 7 q_elliptic, // column 8 q_aux, // column 9 q_lookup, // column 10 @@ -232,7 +232,7 @@ template class UltraRecursiveFlavor_ { // Gemini-specific getters. auto get_unshifted() { - return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, + return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_delta_range, q_elliptic, q_aux, q_lookup, sigma_1, sigma_2, sigma_3, sigma_4, id_1, id_2, id_3, id_4, table_1, table_2, table_3, table_4, lagrange_first, lagrange_last, w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup @@ -241,7 +241,7 @@ template class UltraRecursiveFlavor_ { }; auto get_precomputed() { - return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, + return RefArray{ q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_delta_range, q_elliptic, q_aux, q_lookup, sigma_1, sigma_2, sigma_3, sigma_4, id_1, id_2, id_3, id_4, table_1, table_2, table_3, table_4, lagrange_first, lagrange_last @@ -298,7 +298,7 @@ template class UltraRecursiveFlavor_ { this->q_4 = Commitment::from_witness(builder, native_key->q_4); this->q_c = Commitment::from_witness(builder, native_key->q_c); this->q_arith = Commitment::from_witness(builder, native_key->q_arith); - this->q_sort = Commitment::from_witness(builder, native_key->q_sort); + this->q_delta_range = Commitment::from_witness(builder, native_key->q_delta_range); this->q_elliptic = Commitment::from_witness(builder, native_key->q_elliptic); this->q_aux = Commitment::from_witness(builder, native_key->q_aux); this->q_lookup = Commitment::from_witness(builder, native_key->q_lookup); @@ -355,7 +355,7 @@ template class UltraRecursiveFlavor_ { this->q_4 = "Q_4"; this->q_m = "Q_M"; this->q_arith = "Q_ARITH"; - this->q_sort = "Q_SORT"; + this->q_delta_range = "Q_SORT"; this->q_elliptic = "Q_ELLIPTIC"; this->q_aux = "Q_AUX"; this->q_lookup = "Q_LOOKUP"; @@ -388,7 +388,7 @@ template class UltraRecursiveFlavor_ { this->q_4 = verification_key->q_4; this->q_c = verification_key->q_c; this->q_arith = verification_key->q_arith; - this->q_sort = verification_key->q_sort; + this->q_delta_range = verification_key->q_delta_range; this->q_elliptic = verification_key->q_elliptic; this->q_aux = verification_key->q_aux; this->q_lookup = verification_key->q_lookup; diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/permutation_library.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/permutation_library.hpp index 43ec3081adf..e5b22bffe32 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/permutation_library.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/permutation_library.hpp @@ -222,8 +222,9 @@ template void compute_concatenated_pol * changed ∈ [0 , 2¹⁴ - 1]. To do this, we use several virtual concatenated wires, each of which represents a subset * or original wires (concatenated_range_constraints_). We also generate several new polynomials of the same length * as concatenated ones. These polynomials have values within range, but they are also constrained by the - * GoblinTranslatorFlavor's GenPermSort relation, which ensures that sequential values differ by not more than 3, the - * last value is the maximum and the first value is zero (zero at the start allows us not to dance around shifts). + * GoblinTranslatorFlavor's DeltaRangeConstraint relation, which ensures that sequential values differ by not more than + * 3, the last value is the maximum and the first value is zero (zero at the start allows us not to dance around + * shifts). * * Ideally, we could simply rearrange the values in concatenated_.._0 ,..., concatenated_.._3 and get denominator * polynomials (ordered_constraints), but we could get the worst case scenario: each value in the polynomials is diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index a89f0430bd7..35587e3c208 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -24,7 +24,7 @@ namespace bb { * * struct Component { * using Arithmetic = component::Arithmetic3Wires; - * using RangeConstraints = component::Base4Accumulators or component::GenPerm or... + * using RangeConstraints = component::Base4Accumulators or component::DeltaRangeConstraint or... * using LookupTables = component::Plookup4Wire or component::CQ8Wire or... * ... * }; @@ -142,7 +142,7 @@ template class UltraArith { auto& q_3() { return this->selectors[4]; }; auto& q_4() { return this->selectors[5]; }; auto& q_arith() { return this->selectors[6]; }; - auto& q_sort() { return this->selectors[7]; }; + auto& q_delta_range() { return this->selectors[7]; }; auto& q_elliptic() { return this->selectors[8]; }; auto& q_aux() { return this->selectors[9]; }; auto& q_lookup_type() { return this->selectors[10]; }; @@ -215,7 +215,7 @@ template class UltraHonkArith { auto& q_3() { return this->selectors[4]; }; auto& q_4() { return this->selectors[5]; }; auto& q_arith() { return this->selectors[6]; }; - auto& q_sort() { return this->selectors[7]; }; + auto& q_delta_range() { return this->selectors[7]; }; auto& q_elliptic() { return this->selectors[8]; }; auto& q_aux() { return this->selectors[9]; }; auto& q_lookup_type() { return this->selectors[10]; }; @@ -254,7 +254,8 @@ template class UltraHonkArith { UltraHonkTraceBlock ecc_op; UltraHonkTraceBlock pub_inputs; UltraHonkTraceBlock arithmetic; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/919): Change: GenPermSort --> DeltaRangeConstraint + // TODO(https://github.com/AztecProtocol/barretenberg/issues/919): Change: DeltaRangeConstraint --> + // DeltaRangeConstraint UltraHonkTraceBlock delta_range; UltraHonkTraceBlock elliptic; UltraHonkTraceBlock aux; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index 6d7d474da8a..b845a817bb0 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -50,7 +50,7 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ this->blocks.poseidon_external.q_c().emplace_back(0); this->blocks.poseidon_external.q_arith().emplace_back(0); this->blocks.poseidon_external.q_4().emplace_back(0); - this->blocks.poseidon_external.q_sort().emplace_back(0); + this->blocks.poseidon_external.q_delta_range().emplace_back(0); this->blocks.poseidon_external.q_lookup_type().emplace_back(0); this->blocks.poseidon_external.q_elliptic().emplace_back(0); this->blocks.poseidon_external.q_aux().emplace_back(0); @@ -73,7 +73,7 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ this->blocks.poseidon_internal.q_c().emplace_back(0); this->blocks.poseidon_internal.q_arith().emplace_back(0); this->blocks.poseidon_internal.q_4().emplace_back(0); - this->blocks.poseidon_internal.q_sort().emplace_back(0); + this->blocks.poseidon_internal.q_delta_range().emplace_back(0); this->blocks.poseidon_internal.q_lookup_type().emplace_back(0); this->blocks.poseidon_internal.q_elliptic().emplace_back(0); this->blocks.poseidon_internal.q_aux().emplace_back(0); @@ -239,7 +239,7 @@ void GoblinUltraCircuitBuilder_::create_calldata_lookup_gate(const databus_l block.q_2().emplace_back(0); block.q_3().emplace_back(0); block.q_c().emplace_back(0); - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_arith().emplace_back(0); block.q_4().emplace_back(0); block.q_lookup_type().emplace_back(0); @@ -267,7 +267,7 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseid block.q_c().emplace_back(0); block.q_arith().emplace_back(0); block.q_4().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][3]); - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(0); block.q_aux().emplace_back(0); @@ -293,7 +293,7 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid block.q_c().emplace_back(0); block.q_arith().emplace_back(0); block.q_4().emplace_back(0); - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(0); block.q_aux().emplace_back(0); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp index baa8d032a0b..258a0dfed15 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp @@ -67,7 +67,7 @@ void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_no blocks.arithmetic.q_3().emplace_back(1); blocks.arithmetic.q_4().emplace_back(1); blocks.arithmetic.q_c().emplace_back(0); - blocks.arithmetic.q_sort().emplace_back(0); + blocks.arithmetic.q_delta_range().emplace_back(0); blocks.arithmetic.q_arith().emplace_back(0); blocks.arithmetic.q_lookup_type().emplace_back(0); blocks.arithmetic.q_elliptic().emplace_back(0); @@ -78,7 +78,7 @@ void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_no check_selector_length_consistency(); ++this->num_gates; - // q_sort + // q_delta_range blocks.delta_range.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); blocks.delta_range.q_m().emplace_back(0); blocks.delta_range.q_1().emplace_back(0); @@ -86,7 +86,7 @@ void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_no blocks.delta_range.q_3().emplace_back(0); blocks.delta_range.q_4().emplace_back(0); blocks.delta_range.q_c().emplace_back(0); - blocks.delta_range.q_sort().emplace_back(1); + blocks.delta_range.q_delta_range().emplace_back(1); blocks.delta_range.q_arith().emplace_back(0); blocks.delta_range.q_lookup_type().emplace_back(0); blocks.delta_range.q_elliptic().emplace_back(0); @@ -106,7 +106,7 @@ void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_no blocks.elliptic.q_3().emplace_back(0); blocks.elliptic.q_4().emplace_back(0); blocks.elliptic.q_c().emplace_back(0); - blocks.elliptic.q_sort().emplace_back(0); + blocks.elliptic.q_delta_range().emplace_back(0); blocks.elliptic.q_arith().emplace_back(0); blocks.elliptic.q_lookup_type().emplace_back(0); blocks.elliptic.q_elliptic().emplace_back(1); @@ -126,7 +126,7 @@ void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_no blocks.aux.q_3().emplace_back(0); blocks.aux.q_4().emplace_back(0); blocks.aux.q_c().emplace_back(0); - blocks.aux.q_sort().emplace_back(0); + blocks.aux.q_delta_range().emplace_back(0); blocks.aux.q_arith().emplace_back(0); blocks.aux.q_lookup_type().emplace_back(0); blocks.aux.q_elliptic().emplace_back(0); @@ -184,7 +184,7 @@ void UltraCircuitBuilder_::create_add_gate(const add_triple_::create_big_add_gate(const add_quad_< blocks.arithmetic.q_c().emplace_back(in.const_scaling); blocks.arithmetic.q_arith().emplace_back(include_next_gate_w_4 ? 2 : 1); blocks.arithmetic.q_4().emplace_back(in.d_scaling); - blocks.arithmetic.q_sort().emplace_back(0); + blocks.arithmetic.q_delta_range().emplace_back(0); blocks.arithmetic.q_lookup_type().emplace_back(0); blocks.arithmetic.q_elliptic().emplace_back(0); blocks.arithmetic.q_aux().emplace_back(0); @@ -310,7 +310,7 @@ void UltraCircuitBuilder_::create_big_mul_gate(const mul_quad_< blocks.arithmetic.q_c().emplace_back(in.const_scaling); blocks.arithmetic.q_arith().emplace_back(1); blocks.arithmetic.q_4().emplace_back(in.d_scaling); - blocks.arithmetic.q_sort().emplace_back(0); + blocks.arithmetic.q_delta_range().emplace_back(0); blocks.arithmetic.q_lookup_type().emplace_back(0); blocks.arithmetic.q_elliptic().emplace_back(0); blocks.arithmetic.q_aux().emplace_back(0); @@ -336,7 +336,7 @@ void UltraCircuitBuilder_::create_balanced_add_gate(const add_q blocks.arithmetic.q_c().emplace_back(in.const_scaling); blocks.arithmetic.q_arith().emplace_back(1); blocks.arithmetic.q_4().emplace_back(in.d_scaling); - blocks.arithmetic.q_sort().emplace_back(0); + blocks.arithmetic.q_delta_range().emplace_back(0); blocks.arithmetic.q_lookup_type().emplace_back(0); blocks.arithmetic.q_elliptic().emplace_back(0); blocks.arithmetic.q_aux().emplace_back(0); @@ -378,7 +378,7 @@ void UltraCircuitBuilder_::create_mul_gate(const mul_triple_::create_bool_gate(const uint32_t vari blocks.arithmetic.q_2().emplace_back(0); blocks.arithmetic.q_3().emplace_back(0); blocks.arithmetic.q_c().emplace_back(0); - blocks.arithmetic.q_sort().emplace_back(0); + blocks.arithmetic.q_delta_range().emplace_back(0); blocks.arithmetic.q_arith().emplace_back(1); blocks.arithmetic.q_4().emplace_back(0); @@ -435,7 +435,7 @@ void UltraCircuitBuilder_::create_poly_gate(const poly_triple_< blocks.arithmetic.q_2().emplace_back(in.q_r); blocks.arithmetic.q_3().emplace_back(in.q_o); blocks.arithmetic.q_c().emplace_back(in.q_c); - blocks.arithmetic.q_sort().emplace_back(0); + blocks.arithmetic.q_delta_range().emplace_back(0); blocks.arithmetic.q_arith().emplace_back(1); blocks.arithmetic.q_4().emplace_back(0); @@ -497,7 +497,7 @@ void UltraCircuitBuilder_::create_ecc_add_gate(const ecc_add_ga block.q_2().emplace_back(0); block.q_m().emplace_back(0); block.q_c().emplace_back(0); - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(1); block.q_aux().emplace_back(0); @@ -551,7 +551,7 @@ void UltraCircuitBuilder_::create_ecc_dbl_gate(const ecc_dbl_ga block.q_c().emplace_back(0); block.q_arith().emplace_back(0); block.q_4().emplace_back(0); - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { @@ -582,7 +582,7 @@ void UltraCircuitBuilder_::fix_witness(const uint32_t witness_i blocks.arithmetic.q_c().emplace_back(-witness_value); blocks.arithmetic.q_arith().emplace_back(1); blocks.arithmetic.q_4().emplace_back(0); - blocks.arithmetic.q_sort().emplace_back(0); + blocks.arithmetic.q_delta_range().emplace_back(0); blocks.arithmetic.q_lookup_type().emplace_back(0); blocks.arithmetic.q_elliptic().emplace_back(0); blocks.arithmetic.q_aux().emplace_back(0); @@ -658,7 +658,7 @@ plookup::ReadData UltraCircuitBuilder_::create_gates_ blocks.lookup.q_c().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_3_step_sizes[i + 1])); blocks.lookup.q_arith().emplace_back(0); blocks.lookup.q_4().emplace_back(0); - blocks.lookup.q_sort().emplace_back(0); + blocks.lookup.q_delta_range().emplace_back(0); blocks.lookup.q_elliptic().emplace_back(0); blocks.lookup.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { @@ -967,7 +967,7 @@ void UltraCircuitBuilder_::create_sort_constraint(const std::ve blocks.delta_range.q_c().emplace_back(0); blocks.delta_range.q_arith().emplace_back(0); blocks.delta_range.q_4().emplace_back(0); - blocks.delta_range.q_sort().emplace_back(1); + blocks.delta_range.q_delta_range().emplace_back(1); blocks.delta_range.q_elliptic().emplace_back(0); blocks.delta_range.q_lookup_type().emplace_back(0); blocks.delta_range.q_aux().emplace_back(0); @@ -1001,7 +1001,7 @@ void UltraCircuitBuilder_::create_dummy_gate( block.q_c().emplace_back(0); block.q_arith().emplace_back(0); block.q_4().emplace_back(0); - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_elliptic().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_aux().emplace_back(0); @@ -1059,7 +1059,7 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( block.q_c().emplace_back(0); block.q_arith().emplace_back(0); block.q_4().emplace_back(0); - block.q_sort().emplace_back(1); + block.q_delta_range().emplace_back(1); block.q_elliptic().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_aux().emplace_back(0); @@ -1082,7 +1082,7 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( block.q_c().emplace_back(0); block.q_arith().emplace_back(0); block.q_4().emplace_back(0); - block.q_sort().emplace_back(1); + block.q_delta_range().emplace_back(1); block.q_elliptic().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_aux().emplace_back(0); @@ -1203,7 +1203,7 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT { auto& block = blocks.aux; block.q_aux().emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(0); switch (type) { @@ -1620,7 +1620,7 @@ std::array UltraCircuitBuilder_::evaluate_non_nati blocks.aux.q_c().emplace_back(0); blocks.aux.q_arith().emplace_back(2); blocks.aux.q_4().emplace_back(-LIMB_SHIFT.sqr()); - blocks.aux.q_sort().emplace_back(0); + blocks.aux.q_delta_range().emplace_back(0); blocks.aux.q_lookup_type().emplace_back(0); blocks.aux.q_elliptic().emplace_back(0); blocks.aux.q_aux().emplace_back(0); @@ -1904,7 +1904,7 @@ std::array UltraCircuitBuilder_::evaluate_non_nati block.q_arith().emplace_back(1); for (size_t i = 0; i < 4; ++i) { - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(0); block.q_aux().emplace_back(0); @@ -2024,7 +2024,7 @@ std::array UltraCircuitBuilder_::evaluate_non_nati block.q_arith().emplace_back(1); for (size_t i = 0; i < 4; ++i) { - block.q_sort().emplace_back(0); + block.q_delta_range().emplace_back(0); block.q_lookup_type().emplace_back(0); block.q_elliptic().emplace_back(0); block.q_aux().emplace_back(0); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp index 390ccd71779..b9fd0f9d8c0 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner.test.cpp @@ -23,7 +23,7 @@ TEST(Protogalaxy, CombinerOn2Instances) const auto restrict_to_standard_arithmetic_relation = [](auto& polys) { std::fill(polys.q_arith.begin(), polys.q_arith.end(), 1); - std::fill(polys.q_sort.begin(), polys.q_sort.end(), 0); + std::fill(polys.q_delta_range.begin(), polys.q_delta_range.end(), 0); std::fill(polys.q_elliptic.begin(), polys.q_elliptic.end(), 0); std::fill(polys.q_aux.begin(), polys.q_aux.end(), 0); std::fill(polys.q_lookup.begin(), polys.q_lookup.end(), 0); @@ -151,7 +151,7 @@ TEST(Protogalaxy, CombinerOn4Instances) const auto zero_all_selectors = [](auto& polys) { std::fill(polys.q_arith.begin(), polys.q_arith.end(), 0); - std::fill(polys.q_sort.begin(), polys.q_sort.end(), 0); + std::fill(polys.q_delta_range.begin(), polys.q_delta_range.end(), 0); std::fill(polys.q_elliptic.begin(), polys.q_elliptic.end(), 0); std::fill(polys.q_aux.begin(), polys.q_aux.end(), 0); std::fill(polys.q_lookup.begin(), polys.q_lookup.end(), 0); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py index ac701d41e95..0ace782160a 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/combiner_example_gen.py @@ -15,7 +15,7 @@ def __init__(self, start): self.q_4 = start + 2 * 4 self.q_m = start + 2 * 5 self.q_arith = start + 2 * 6 - self.q_sort = start + 2 * 7 + self.q_delta_range = start + 2 * 7 self.q_elliptic = start + 2 * 8 self.q_aux = start + 2 * 9 self.q_lookup = start + 2 * 10 diff --git a/barretenberg/cpp/src/barretenberg/relations/gen_perm_sort_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/delta_range_constraint_relation.hpp similarity index 87% rename from barretenberg/cpp/src/barretenberg/relations/gen_perm_sort_relation.hpp rename to barretenberg/cpp/src/barretenberg/relations/delta_range_constraint_relation.hpp index 2da286ee3e2..dee7759db07 100644 --- a/barretenberg/cpp/src/barretenberg/relations/gen_perm_sort_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/delta_range_constraint_relation.hpp @@ -3,7 +3,7 @@ namespace bb { -template class GenPermSortRelationImpl { +template class DeltaRangeConstraintRelationImpl { public: using FF = FF_; @@ -17,7 +17,7 @@ template class GenPermSortRelationImpl { /** * @brief Expression for the generalized permutation sort gate. * @details The relation is defined as C(in(X)...) = - * q_sort * \sum{ i = [0, 3]} \alpha^i D_i(D_i - 1)(D_i - 2)(D_i - 3) + * q_delta_range * \sum{ i = [0, 3]} \alpha^i D_i(D_i - 1)(D_i - 2)(D_i - 3) * where * D_0 = w_2 - w_1 * D_1 = w_3 - w_2 @@ -42,7 +42,7 @@ template class GenPermSortRelationImpl { auto w_3 = View(in.w_o); auto w_4 = View(in.w_4); auto w_1_shift = View(in.w_l_shift); - auto q_sort = View(in.q_sort); + auto q_delta_range = View(in.q_delta_range); static const FF minus_one = FF(-1); static const FF minus_two = FF(-2); @@ -59,7 +59,7 @@ template class GenPermSortRelationImpl { tmp_1 *= (delta_1 + minus_one); tmp_1 *= (delta_1 + minus_two); tmp_1 *= (delta_1 + minus_three); - tmp_1 *= q_sort; + tmp_1 *= q_delta_range; tmp_1 *= scaling_factor; std::get<0>(accumulators) += tmp_1; @@ -68,7 +68,7 @@ template class GenPermSortRelationImpl { tmp_2 *= (delta_2 + minus_one); tmp_2 *= (delta_2 + minus_two); tmp_2 *= (delta_2 + minus_three); - tmp_2 *= q_sort; + tmp_2 *= q_delta_range; tmp_2 *= scaling_factor; std::get<1>(accumulators) += tmp_2; @@ -77,7 +77,7 @@ template class GenPermSortRelationImpl { tmp_3 *= (delta_3 + minus_one); tmp_3 *= (delta_3 + minus_two); tmp_3 *= (delta_3 + minus_three); - tmp_3 *= q_sort; + tmp_3 *= q_delta_range; tmp_3 *= scaling_factor; std::get<2>(accumulators) += tmp_3; @@ -86,12 +86,12 @@ template class GenPermSortRelationImpl { tmp_4 *= (delta_4 + minus_one); tmp_4 *= (delta_4 + minus_two); tmp_4 *= (delta_4 + minus_three); - tmp_4 *= q_sort; + tmp_4 *= q_delta_range; tmp_4 *= scaling_factor; std::get<3>(accumulators) += tmp_4; }; }; -template using GenPermSortRelation = Relation>; +template using DeltaRangeConstraintRelation = Relation>; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/goblin_translator_relation_consistency.test.cpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/goblin_translator_relation_consistency.test.cpp index 890810aee0a..2f55d2d8885 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/goblin_translator_relation_consistency.test.cpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/goblin_translator_relation_consistency.test.cpp @@ -102,10 +102,10 @@ TEST_F(GoblinTranslatorRelationConsistency, PermutationRelation) run_test(/*random_inputs=*/true); }; -TEST_F(GoblinTranslatorRelationConsistency, GenPermSortRelation) +TEST_F(GoblinTranslatorRelationConsistency, DeltaRangeConstraintRelation) { const auto run_test = [](bool random_inputs) { - using Relation = GoblinTranslatorGenPermSortRelation; + using Relation = GoblinTranslatorDeltaRangeConstraintRelation; using RelationValues = typename Relation::SumcheckArrayOfValuesOverSubrelations; const InputElements input_elements = random_inputs ? get_random_input() : get_special_input(); diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.cpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.cpp similarity index 89% rename from barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.cpp rename to barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.cpp index fe5c222a8cc..70c0456e884 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.cpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.hpp" +#include "barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp" #include "barretenberg/flavor/goblin_translator.hpp" namespace bb { @@ -17,10 +17,10 @@ namespace bb { */ template template -void GoblinTranslatorGenPermSortRelationImpl::accumulate(ContainerOverSubrelations& accumulators, - const AllEntities& in, - const Parameters&, - const FF& scaling_factor) +void GoblinTranslatorDeltaRangeConstraintRelationImpl::accumulate(ContainerOverSubrelations& accumulators, + const AllEntities& in, + const Parameters&, + const FF& scaling_factor) { static const FF minus_one = FF(-1); static const FF minus_two = FF(-2); @@ -126,7 +126,7 @@ void GoblinTranslatorGenPermSortRelationImpl::accumulate(ContainerOverSubrel }(); }; -template class GoblinTranslatorGenPermSortRelationImpl; -DEFINE_SUMCHECK_RELATION_CLASS(GoblinTranslatorGenPermSortRelationImpl, GoblinTranslatorFlavor); +template class GoblinTranslatorDeltaRangeConstraintRelationImpl; +DEFINE_SUMCHECK_RELATION_CLASS(GoblinTranslatorDeltaRangeConstraintRelationImpl, GoblinTranslatorFlavor); } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp similarity index 91% rename from barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.hpp rename to barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp index 3212cc3925d..01547603e0c 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_gen_perm_sort_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp @@ -3,7 +3,7 @@ namespace bb { -template class GoblinTranslatorGenPermSortRelationImpl { +template class GoblinTranslatorDeltaRangeConstraintRelationImpl { public: using FF = FF_; @@ -44,6 +44,6 @@ template class GoblinTranslatorGenPermSortRelationImpl { }; template -using GoblinTranslatorGenPermSortRelation = Relation>; +using GoblinTranslatorDeltaRangeConstraintRelation = Relation>; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp index 731725d6ee2..79e7349d6b8 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp +++ b/barretenberg/cpp/src/barretenberg/relations/ultra_relation_consistency.test.cpp @@ -14,8 +14,8 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/poseidon2_external_relation.hpp" @@ -56,7 +56,7 @@ struct InputElements { FF& q_4 = std::get<4>(_data); FF& q_m = std::get<5>(_data); FF& q_arith = std::get<6>(_data); - FF& q_sort = std::get<7>(_data); + FF& q_delta_range = std::get<7>(_data); FF& q_elliptic = std::get<8>(_data); FF& q_aux = std::get<9>(_data); FF& q_lookup = std::get<10>(_data); @@ -282,10 +282,10 @@ TEST_F(UltraRelationConsistency, LookupRelation) run_test(/*random_inputs=*/true); }; -TEST_F(UltraRelationConsistency, GenPermSortRelation) +TEST_F(UltraRelationConsistency, DeltaRangeConstraintRelation) { const auto run_test = [](bool random_inputs) { - using Relation = GenPermSortRelation; + using Relation = DeltaRangeConstraintRelation; using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations; const InputElements input_elements = random_inputs ? InputElements::get_random() : InputElements::get_special(); @@ -294,7 +294,7 @@ TEST_F(UltraRelationConsistency, GenPermSortRelation) const auto& w_3 = input_elements.w_o; const auto& w_4 = input_elements.w_4; const auto& w_1_shift = input_elements.w_l_shift; - const auto& q_sort = input_elements.q_sort; + const auto& q_delta_range = input_elements.q_delta_range; auto delta_1 = w_2 - w_1; auto delta_2 = w_3 - w_2; @@ -308,10 +308,10 @@ TEST_F(UltraRelationConsistency, GenPermSortRelation) SumcheckArrayOfValuesOverSubrelations expected_values; - expected_values[0] = contribution_1 * q_sort; - expected_values[1] = contribution_2 * q_sort; - expected_values[2] = contribution_3 * q_sort; - expected_values[3] = contribution_4 * q_sort; + expected_values[0] = contribution_1 * q_delta_range; + expected_values[1] = contribution_2 * q_delta_range; + expected_values[2] = contribution_3 * q_delta_range; + expected_values[3] = contribution_4 * q_delta_range; const auto parameters = RelationParameters::get_random(); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp index 008cbd01570..a3d94d3ac79 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp @@ -2,8 +2,8 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/proof_system/plookup_tables/fixed_base/fixed_base.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp index 2ff86d31da2..85a6eba0bc6 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -4,9 +4,9 @@ #include "barretenberg/honk/proof_system/permutation_library.hpp" #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/ecc_op_queue_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/relation_parameters.hpp" @@ -138,7 +138,7 @@ template void create_some_lookup_gates(auto& circuit_builder) plookup::MultiTableId::FIXED_BASE_LEFT_LO, sequence_data_lo, input_lo_index); } -template void create_some_genperm_sort_gates(auto& circuit_builder) +template void create_some_delta_range_constraint_gates(auto& circuit_builder) { // Add a sort gate (simply checks that consecutive inputs have a difference of < 4) using FF = typename Flavor::FF; @@ -257,7 +257,7 @@ TEST_F(RelationCorrectnessTests, UltraRelationCorrectness) // Create an assortment of representative gates create_some_add_gates(builder); create_some_lookup_gates(builder); - create_some_genperm_sort_gates(builder); + create_some_delta_range_constraint_gates(builder); create_some_elliptic_curve_addition_gates(builder); create_some_RAM_gates(builder); @@ -277,7 +277,7 @@ TEST_F(RelationCorrectnessTests, UltraRelationCorrectness) // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution ensure_non_zero(proving_key->q_arith); - ensure_non_zero(proving_key->q_sort); + ensure_non_zero(proving_key->q_delta_range); ensure_non_zero(proving_key->q_lookup); ensure_non_zero(proving_key->q_elliptic); ensure_non_zero(proving_key->q_aux); @@ -308,7 +308,7 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) // Create an assortment of representative gates create_some_add_gates(builder); create_some_lookup_gates(builder); - create_some_genperm_sort_gates(builder); + create_some_delta_range_constraint_gates(builder); create_some_elliptic_curve_addition_gates(builder); create_some_RAM_gates(builder); create_some_ecc_op_queue_gates(builder); // Goblin! @@ -330,7 +330,7 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution ensure_non_zero(proving_key->q_arith); - ensure_non_zero(proving_key->q_sort); + ensure_non_zero(proving_key->q_delta_range); ensure_non_zero(proving_key->q_lookup); ensure_non_zero(proving_key->q_elliptic); ensure_non_zero(proving_key->q_aux); @@ -481,7 +481,7 @@ TEST_F(RelationCorrectnessTests, GoblinTranslatorPermutationRelationCorrectness) check_relation>(full_circuit_size, prover_polynomials, params); } -TEST_F(RelationCorrectnessTests, GoblinTranslatorGenPermSortRelationCorrectness) +TEST_F(RelationCorrectnessTests, GoblinTranslatorDeltaRangeConstraintRelationCorrectness) { using Flavor = GoblinTranslatorFlavor; using FF = typename Flavor::FF; @@ -502,11 +502,11 @@ TEST_F(RelationCorrectnessTests, GoblinTranslatorGenPermSortRelationCorrectness) polynomial = Polynomial{ circuit_size }; } - // Construct lagrange polynomials that are needed for Goblin Translator's GenPermSort Relation + // Construct lagrange polynomials that are needed for Goblin Translator's DeltaRangeConstraint Relation prover_polynomials.lagrange_first[0] = 1; prover_polynomials.lagrange_last[circuit_size - 1] = 1; - // Create a vector and fill with necessary steps for the GenPermSort relation + // Create a vector and fill with necessary steps for the DeltaRangeConstraint relation auto sorted_elements_count = (max_value / sort_step) + 1; std::vector vector_for_sorting(circuit_size); for (size_t i = 0; i < sorted_elements_count - 1; i++) { @@ -552,7 +552,7 @@ TEST_F(RelationCorrectnessTests, GoblinTranslatorGenPermSortRelationCorrectness) using Relations = typename Flavor::Relations; - // Check that GenPermSort relation is satisfied across each row of the prover polynomials + // Check that DeltaRangeConstraint relation is satisfied across each row of the prover polynomials check_relation>(circuit_size, prover_polynomials, params); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index 69b3285d9d6..4f71fd5ea62 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -4,8 +4,8 @@ #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/proof_system/plookup_tables/fixed_base/fixed_base.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" +#include "barretenberg/relations/delta_range_constraint_relation.hpp" #include "barretenberg/relations/elliptic_relation.hpp" -#include "barretenberg/relations/gen_perm_sort_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" From 424401ce10e15e955175ce559a207c739d3cb2f5 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:09:33 +0000 Subject: [PATCH 17/36] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "fd0490da1" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "fd0490da1" git-subrepo: version: "0.4.6" origin: "???" commit: "???" [skip ci] --- barretenberg/.gitrepo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index f3f66560170..c4d6a34a16d 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 98174952c4912ea876417957f54d832dd4b90a74 - parent = eca12b3a173f9ef1880e3b703ab778beb036a23b + commit = fd0490da1185a51189cfcfb901df51ad9723a808 + parent = 841855fc069b89a5937e63194452f1a3cfd76f5c method = merge cmdver = 0.4.6 From 4447aa9eef5a6891e6c6f653a1e6103ee41c8d3b Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:10:17 +0000 Subject: [PATCH 18/36] chore: replace relative paths to noir-protocol-circuits --- noir-projects/aztec-nr/aztec/Nargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 7a1f1af5863..79ad55aa169 100644 --- a/noir-projects/aztec-nr/aztec/Nargo.toml +++ b/noir-projects/aztec-nr/aztec/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.18.0" type = "lib" [dependencies] -protocol_types = { path = "../../noir-protocol-circuits/crates/types" } +protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.30.1", directory="noir-projects/noir-protocol-circuits/crates/types" } From 08c935809520d73c045759ff2a224f2e5496f73d Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:10:18 +0000 Subject: [PATCH 19/36] git_subrepo.sh: Fix parent in .gitrepo file. [skip ci] --- noir-projects/aztec-nr/.gitrepo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 95ad005f335..83af9852281 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = 0e201e392ba8ac6d5677d79aaeb5b2aeaf2640e0 method = merge cmdver = 0.4.6 - parent = 7fb57905b59df0c68207e93180f8ab5b0f5bb7e7 + parent = 7b6509d0c083b6197f4a95db7831f65ff2b52d20 From 86a63f728e8bb643146ba11e04badadb498b0778 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:10:22 +0000 Subject: [PATCH 20/36] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "423ea499e" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "423ea499e" git-subrepo: version: "0.4.6" origin: "???" commit: "???" [skip ci] --- noir-projects/aztec-nr/.gitrepo | 4 ++-- noir-projects/aztec-nr/aztec/Nargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 83af9852281..7c6ae1c99ed 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = 0e201e392ba8ac6d5677d79aaeb5b2aeaf2640e0 + commit = 423ea499e5b4a0c9795d5fdfd9fb9533432f4b9e method = merge cmdver = 0.4.6 - parent = 7b6509d0c083b6197f4a95db7831f65ff2b52d20 + parent = 522ba628ec919bf8c9f421028ad669e7432e8442 diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 79ad55aa169..7a1f1af5863 100644 --- a/noir-projects/aztec-nr/aztec/Nargo.toml +++ b/noir-projects/aztec-nr/aztec/Nargo.toml @@ -5,4 +5,4 @@ compiler_version = ">=0.18.0" type = "lib" [dependencies] -protocol_types = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.30.1", directory="noir-projects/noir-protocol-circuits/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } From 565f59b23076799b63fb2db85b72a11e3018097a Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:07:50 +0100 Subject: [PATCH 21/36] refactor: make get_notes fail if returning no notes #4988 (#5320) Resolves #4988. --- .../aztec-nr/aztec/src/note/note_getter.nr | 13 ++-- .../pending_note_hashes_contract/src/main.nr | 18 +---- .../src/e2e_blacklist_token_contract.test.ts | 2 +- .../end-to-end/src/e2e_card_game.test.ts | 2 +- .../end-to-end/src/e2e_note_getter.test.ts | 2 +- .../e2e_pending_note_hashes_contract.test.ts | 9 ++- .../end-to-end/src/e2e_static_calls.test.ts | 6 ++ .../end-to-end/src/e2e_token_contract.test.ts | 2 +- .../src/client/private_execution.test.ts | 77 +++++-------------- 9 files changed, 42 insertions(+), 89 deletions(-) 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 70ade0d417b..99c3a2e7872 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -101,9 +101,7 @@ pub fn get_notes( options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let mut opt_notes = get_notes_internal(storage_slot, options); - let mut returned_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; - let mut write_index = 0; let mut num_notes = 0; let mut prev_fields = [0; N]; @@ -124,18 +122,19 @@ pub fn get_notes( // failure if malicious oracle injects 0 nonce here for a "pre-existing" note. context.push_note_hash_read_request(note_hash_for_read_request); - num_notes += 1; // The below code is used to collapse a sparse array into one where the values are guaranteed to be at the front of the array - // The condition activates if at any point there was a gap in the array, (i was advanced; by not write_index) - // In this case we move our note at i to returned_notes at write_index - returned_notes[write_index] = Option::some(note); - write_index += 1; + // We write at returned_notes + returned_notes[num_notes] = Option::some(note); + num_notes += 1; }; } if options.limit != 0 { assert(num_notes <= options.limit, "Invalid number of return notes."); } + + assert(num_notes != 0, "Cannot return zero notes"); + returned_notes } diff --git a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr index a46df1a92db..7d3fcd593b8 100644 --- a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr @@ -110,8 +110,7 @@ contract PendingNoteHashes { amount: Field, owner: AztecAddress, insert_fn_selector: FunctionSelector, - get_then_nullify_fn_selector: FunctionSelector, - get_note_zero_fn_selector: FunctionSelector + get_then_nullify_fn_selector: FunctionSelector ) { // nested call to create/insert note let _callStackItem1 = context.call_private_function( @@ -125,12 +124,6 @@ contract PendingNoteHashes { get_then_nullify_fn_selector, [amount, owner.to_field()] ); - // nested call to confirm that balance is zero - let _callStackItem3 = context.call_private_function( - inputs.call_context.storage_contract_address, - get_note_zero_fn_selector, - [owner.to_field()] - ); } // same test as above, but insert 2, get 2, nullify 2 @@ -209,8 +202,7 @@ contract PendingNoteHashes { amount: Field, owner: AztecAddress, insert_fn_selector: FunctionSelector, - get_then_nullify_fn_selector: FunctionSelector, - get_note_zero_fn_selector: FunctionSelector + get_then_nullify_fn_selector: FunctionSelector ) { // args for nested calls let args = [amount, owner.to_field()]; @@ -232,12 +224,6 @@ contract PendingNoteHashes { get_then_nullify_fn_selector, args ); - - let _callStackItem4 = context.call_private_function( - inputs.call_context.storage_contract_address, - get_note_zero_fn_selector, - [owner.to_field()] - ); } // Confirm cannot get/read a pending note hash in a nested call // that is created/inserted later in execution but in the parent. diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts index 8d6e232fbb1..efb35e65902 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts @@ -389,7 +389,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); await expect(asset.methods.redeem_shield(accounts[0].address, amount, secret).simulate()).rejects.toThrow( - 'Can only remove a note that has been read from the set.', + `Assertion failed: Cannot return zero notes`, ); }); diff --git a/yarn-project/end-to-end/src/e2e_card_game.test.ts b/yarn-project/end-to-end/src/e2e_card_game.test.ts index 6e26b459fad..1520f91c92a 100644 --- a/yarn-project/end-to-end/src/e2e_card_game.test.ts +++ b/yarn-project/end-to-end/src/e2e_card_game.test.ts @@ -172,7 +172,7 @@ describe('e2e_card_game', () => { .join_game(GAME_ID, [cardToField(firstPlayerCollection[0]), cardToField(firstPlayerCollection[1])]) .send() .wait(), - ).rejects.toThrow(/Card not found/); + ).rejects.toThrow(`Assertion failed: Cannot return zero notes`); const collection = await contract.methods.view_collection_cards(firstPlayer, 0).view({ from: firstPlayer }); expect(unwrapOptions(collection)).toHaveLength(1); diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 162c453929d..9406521fff3 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -177,7 +177,7 @@ describe('e2e_note_getter', () => { async function assertNoReturnValue(storageSlot: number, activeOrNullified: boolean) { await expect(contract.methods.call_view_notes(storageSlot, activeOrNullified).view()).rejects.toThrow('is_some'); await expect(contract.methods.call_get_notes(storageSlot, activeOrNullified).send().wait()).rejects.toThrow( - 'is_some', + `Assertion failed: Cannot return zero notes`, ); } diff --git a/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts index 37e1cbdefdb..1e30daec290 100644 --- a/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts @@ -79,10 +79,12 @@ describe('e2e_pending_note_hashes_contract', () => { owner, deployedContract.methods.insert_note.selector, deployedContract.methods.get_then_nullify_note.selector, - deployedContract.methods.get_note_zero_balance.selector, ) .send() .wait(); + await expect(deployedContract.methods.get_note_zero_balance(owner).send().wait()).rejects.toThrow( + `Assertion failed: Cannot return zero notes`, + ); await expectNoteHashesSquashedExcept(0); await expectNullifiersSquashedExcept(0); @@ -154,10 +156,12 @@ describe('e2e_pending_note_hashes_contract', () => { owner, deployedContract.methods.insert_note.selector, deployedContract.methods.get_then_nullify_note.selector, - deployedContract.methods.get_note_zero_balance.selector, ) .send() .wait(); + await expect(deployedContract.methods.get_note_zero_balance(owner).send().wait()).rejects.toThrow( + `Assertion failed: Cannot return zero notes`, + ); // second TX creates 1 note, but it is squashed! await expectNoteHashesSquashedExcept(0); @@ -186,7 +190,6 @@ describe('e2e_pending_note_hashes_contract', () => { owner, deployedContract.methods.dummy.selector, deployedContract.methods.get_then_nullify_note.selector, - deployedContract.methods.get_note_zero_balance.selector, ) .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 974d3ce3f45..6461ce22a6f 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 @@ -22,6 +22,9 @@ 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(); + // ...this call doesn't fail due to get_notes returning 0 notes await parentContract.methods .privateStaticCall(childContract.address, childContract.methods.privateGetValue.selector, [ 42n, @@ -32,6 +35,9 @@ describe('e2e_static_calls', () => { }, 100_000); 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(); + // ...this call doesn't fail due to get_notes returning 0 notes await parentContract.methods .privateStaticCallNested(childContract.address, childContract.methods.privateGetValue.selector, [ 42n, diff --git a/yarn-project/end-to-end/src/e2e_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_token_contract.test.ts index a64490a6571..f7e60748f2e 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract.test.ts @@ -275,7 +275,7 @@ describe('e2e_token_contract', () => { 'The note has been destroyed.', ); await expect(asset.methods.redeem_shield(accounts[0].address, amount, secret).simulate()).rejects.toThrow( - 'Can only remove a note that has been read from the set.', + `Assertion failed: Cannot return zero notes`, ); }); diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 2abe169627f..32b6d1f8b86 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -918,27 +918,15 @@ describe('Private Execution test suite', () => { const getThenNullifyArtifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'get_then_nullify_note'); - const getZeroArtifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'get_note_zero_balance'); - const insertFnSelector = FunctionSelector.fromNameAndParameters(insertArtifact.name, insertArtifact.parameters); const getThenNullifyFnSelector = FunctionSelector.fromNameAndParameters( getThenNullifyArtifact.name, getThenNullifyArtifact.parameters, ); - const getZeroFnSelector = FunctionSelector.fromNameAndParameters( - getZeroArtifact.name, - getZeroArtifact.parameters, - ); oracle.getPortalContractAddress.mockImplementation(() => Promise.resolve(EthAddress.ZERO)); - const args = [ - amountToTransfer, - owner, - insertFnSelector.toField(), - getThenNullifyFnSelector.toField(), - getZeroFnSelector.toField(), - ]; + const args = [amountToTransfer, owner, insertFnSelector.toField(), getThenNullifyFnSelector.toField()]; const result = await runSimulator({ args: args, artifact: artifact, @@ -947,7 +935,6 @@ describe('Private Execution test suite', () => { const execInsert = result.nestedExecutions[0]; const execGetThenNullify = result.nestedExecutions[1]; - const getNotesAfterNullify = result.nestedExecutions[2]; const storageSlot = computeSlotForMapping(new Fr(1n), owner); const noteTypeId = new Fr(869710811710178111116101n); // ValueNote @@ -991,10 +978,6 @@ describe('Private Execution test suite', () => { siloedNullifierSecretKey.high, ]); expect(nullifier.value).toEqual(expectedNullifier); - - // check that the last get_notes call return no note - const afterNullifyingNoteValue = getNotesAfterNullify.callStackItem.publicInputs.returnValues[0].value; - expect(afterNullifyingNoteValue).toEqual(0n); }); it('cant read a commitment that is inserted later in same call', async () => { @@ -1007,48 +990,13 @@ describe('Private Execution test suite', () => { const artifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'test_bad_get_then_insert_flat'); const args = [amountToTransfer, owner]; - const result = await runSimulator({ - args: args, - artifact: artifact, - contractAddress, - }); - - const storageSlot = computeSlotForMapping(new Fr(1n), owner); - const noteTypeId = new Fr(869710811710178111116101n); // ValueNote - - expect(result.newNotes).toHaveLength(1); - const noteAndSlot = result.newNotes[0]; - expect(noteAndSlot.storageSlot).toEqual(storageSlot); - expect(noteAndSlot.noteTypeId).toEqual(noteTypeId); - - expect(noteAndSlot.note.items[0]).toEqual(new Fr(amountToTransfer)); - - const newNoteHashes = sideEffectArrayToValueArray( - nonEmptySideEffects(result.callStackItem.publicInputs.newNoteHashes), - ); - expect(newNoteHashes).toHaveLength(1); - - const noteHash = newNoteHashes[0]; - expect(noteHash).toEqual( - await acirSimulator.computeInnerNoteHash( + await expect( + runSimulator({ + args: args, + artifact: artifact, contractAddress, - storageSlot, - noteAndSlot.noteTypeId, - noteAndSlot.note, - ), - ); - - // read requests should be empty - const readRequest = result.callStackItem.publicInputs.noteHashReadRequests[0].value; - expect(readRequest).toEqual(Fr.ZERO); - - // should get note value 0 because it actually gets a fake note since the real one hasn't been inserted yet! - const gotNoteValue = result.callStackItem.publicInputs.returnValues[0]; - expect(gotNoteValue).toEqual(Fr.ZERO); - - // there should be no nullifiers - const nullifier = result.callStackItem.publicInputs.newNullifiers[0].value; - expect(nullifier).toEqual(Fr.ZERO); + }), + ).rejects.toThrow(`Assertion failed: Cannot return zero notes`); }); }); @@ -1069,6 +1017,17 @@ describe('Private Execution test suite', () => { }); }); + describe('Get notes', () => { + it('fails if returning no notes', async () => { + const artifact = getFunctionArtifact(TestContractArtifact, 'call_get_notes'); + + const args = [2n, true]; + oracle.getNotes.mockResolvedValue([]); + + await expect(runSimulator({ artifact, args })).rejects.toThrow(`Assertion failed: Cannot return zero notes`); + }); + }); + describe('Context oracles', () => { it("Should be able to get and return the contract's portal contract address", async () => { const portalContractAddress = EthAddress.random(); From 784585ab384c4aed4d4faf16f9638dd5320e17f2 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:59:36 +0000 Subject: [PATCH 22/36] feat(AuthWit): chain_id and version in hash (#5331) Fixes #5074 by including the `chain_id` and `version` as part of the message hash that we are signing over in the authwits. --- noir-projects/aztec-nr/authwit/src/account.nr | 4 +- noir-projects/aztec-nr/authwit/src/auth.nr | 25 ++++- .../contracts/uniswap_contract/src/main.nr | 4 +- .../src/defaults/account_interface.ts | 16 ++- .../accounts/src/ecdsa/account_contract.ts | 6 +- .../accounts/src/schnorr/account_contract.ts | 6 +- .../src/single_key/account_contract.ts | 6 +- .../aztec.js/src/account/interface.ts | 12 ++ .../src/fee/private_fee_payment_method.ts | 15 ++- .../src/fee/public_fee_payment_method.ts | 22 ++-- yarn-project/aztec.js/src/utils/authwit.ts | 16 ++- .../aztec.js/src/wallet/account_wallet.ts | 40 ++++++- .../aztec.js/src/wallet/base_wallet.ts | 8 ++ .../aztec.js/src/wallet/signerless_wallet.ts | 10 +- .../end-to-end/src/e2e_authwit.test.ts | 103 +++++++++++++++++- .../src/e2e_blacklist_token_contract.test.ts | 35 +++++- .../src/e2e_cross_chain_messaging.test.ts | 2 + .../src/e2e_crowdfunding_and_claim.test.ts | 4 +- yarn-project/end-to-end/src/e2e_fees.test.ts | 42 ++++--- .../src/e2e_lending_contract.test.ts | 2 + .../e2e_public_cross_chain_messaging.test.ts | 2 + .../end-to-end/src/e2e_token_contract.test.ts | 43 ++++++-- .../writing_an_account_contract.test.ts | 6 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 26 ++++- .../entrypoints/src/dapp_entrypoint.ts | 7 +- 25 files changed, 381 insertions(+), 81 deletions(-) diff --git a/noir-projects/aztec-nr/authwit/src/account.nr b/noir-projects/aztec-nr/authwit/src/account.nr index 2a25420feaf..b8a62fb6653 100644 --- a/noir-projects/aztec-nr/authwit/src/account.nr +++ b/noir-projects/aztec-nr/authwit/src/account.nr @@ -76,7 +76,7 @@ impl AccountActions { // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can // consume the message. // This ensures that contracts cannot consume messages that are not intended for them. - let message_hash = compute_outer_authwit_hash(context.msg_sender(), inner_hash); + let message_hash = compute_outer_authwit_hash(context.msg_sender(), context.chain_id(), context.version(), inner_hash); let valid_fn = self.is_valid_impl; assert(valid_fn(context, message_hash) == true, "Message not authorized by account"); context.push_new_nullifier(message_hash, 0); @@ -90,7 +90,7 @@ impl AccountActions { // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can // consume the message. // This ensures that contracts cannot consume messages that are not intended for them. - let message_hash = compute_outer_authwit_hash(context.msg_sender(), inner_hash); + let message_hash = compute_outer_authwit_hash(context.msg_sender(), context.chain_id(), context.version(), inner_hash); let is_valid = self.approved_action.at(message_hash).read(); assert(is_valid == true, "Message not authorized by account"); context.push_new_nullifier(message_hash, 0); diff --git a/noir-projects/aztec-nr/authwit/src/auth.nr b/noir-projects/aztec-nr/authwit/src/auth.nr index e098fdd5fd7..90972c94d7b 100644 --- a/noir-projects/aztec-nr/authwit/src/auth.nr +++ b/noir-projects/aztec-nr/authwit/src/auth.nr @@ -29,10 +29,17 @@ pub fn assert_current_call_valid_authwit_public(context: &mut PublicContext, on_ // docs:start:compute_call_authwit_hash // Compute the message hash to be used by an authentication witness -pub fn compute_call_authwit_hash(caller: AztecAddress, consumer: AztecAddress, selector: FunctionSelector, args: [Field; N]) -> Field { +pub fn compute_call_authwit_hash( + caller: AztecAddress, + consumer: AztecAddress, + chain_id: Field, + version: Field, + selector: FunctionSelector, + args: [Field; N] +) -> Field { let args_hash = hash_args(args); let inner_hash = compute_inner_authwit_hash([caller.to_field(), selector.to_field(), args_hash]); - compute_outer_authwit_hash(consumer, inner_hash) + compute_outer_authwit_hash(consumer, chain_id, version, inner_hash) } // docs:end:compute_call_authwit_hash @@ -40,9 +47,19 @@ pub fn compute_inner_authwit_hash(args: [Field; N]) -> Field { pedersen_hash(args, GENERATOR_INDEX__AUTHWIT_INNER) } -pub fn compute_outer_authwit_hash(consumer: AztecAddress, inner_hash: Field) -> Field { +pub fn compute_outer_authwit_hash( + consumer: AztecAddress, + chain_id: Field, + version: Field, + inner_hash: Field +) -> Field { pedersen_hash( - [consumer.to_field(), inner_hash], + [ + consumer.to_field(), + chain_id, + version, + inner_hash + ], GENERATOR_INDEX__AUTHWIT_OUTER ) } diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr index c092d6bf081..c6a08d9c2bd 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -166,7 +166,7 @@ contract Uniswap { // if valid, it returns the IS_VALID selector which is expected by token contract #[aztec(public)] fn spend_public_authwit(inner_hash: Field) -> Field { - let message_hash = compute_outer_authwit_hash(context.msg_sender(), inner_hash); + let message_hash = compute_outer_authwit_hash(context.msg_sender(), context.chain_id(), context.version(), inner_hash); let value = storage.approved_action.at(message_hash).read(); if (value) { context.push_new_nullifier(message_hash, 0); @@ -192,6 +192,8 @@ contract Uniswap { let message_hash = compute_call_authwit_hash( token_bridge, token, + context.chain_id(), + context.version(), selector, [context.this_address().to_field(), amount, nonce_for_burn_approval] ); diff --git a/yarn-project/accounts/src/defaults/account_interface.ts b/yarn-project/accounts/src/defaults/account_interface.ts index f37833ea9a7..e3a952f1540 100644 --- a/yarn-project/accounts/src/defaults/account_interface.ts +++ b/yarn-project/accounts/src/defaults/account_interface.ts @@ -10,6 +10,8 @@ import { NodeInfo } from '@aztec/types/interfaces'; */ export class DefaultAccountInterface implements AccountInterface { private entrypoint: EntrypointInterface; + private chainId: Fr; + private version: Fr; constructor( private authWitnessProvider: AuthWitnessProvider, @@ -22,14 +24,16 @@ export class DefaultAccountInterface implements AccountInterface { nodeInfo.chainId, nodeInfo.protocolVersion, ); + this.chainId = new Fr(nodeInfo.chainId); + this.version = new Fr(nodeInfo.protocolVersion); } createTxExecutionRequest(executions: FunctionCall[], fee?: FeeOptions): Promise { return this.entrypoint.createTxExecutionRequest(executions, fee); } - createAuthWit(message: Fr): Promise { - return this.authWitnessProvider.createAuthWit(message); + createAuthWit(messageHash: Fr): Promise { + return this.authWitnessProvider.createAuthWit(messageHash); } getCompleteAddress(): CompleteAddress { @@ -39,4 +43,12 @@ export class DefaultAccountInterface implements AccountInterface { getAddress(): AztecAddress { return this.address.address; } + + getChainId(): Fr { + return this.chainId; + } + + getVersion(): Fr { + return this.version; + } } diff --git a/yarn-project/accounts/src/ecdsa/account_contract.ts b/yarn-project/accounts/src/ecdsa/account_contract.ts index 22c28d699a4..7919ecf62a3 100644 --- a/yarn-project/accounts/src/ecdsa/account_contract.ts +++ b/yarn-project/accounts/src/ecdsa/account_contract.ts @@ -30,9 +30,9 @@ export class EcdsaAccountContract extends DefaultAccountContract { class EcdsaAuthWitnessProvider implements AuthWitnessProvider { constructor(private signingPrivateKey: Buffer) {} - createAuthWit(message: Fr): Promise { + createAuthWit(messageHash: Fr): Promise { const ecdsa = new Ecdsa(); - const signature = ecdsa.constructSignature(message.toBuffer(), this.signingPrivateKey); - return Promise.resolve(new AuthWitness(message, [...signature.r, ...signature.s])); + const signature = ecdsa.constructSignature(messageHash.toBuffer(), this.signingPrivateKey); + return Promise.resolve(new AuthWitness(messageHash, [...signature.r, ...signature.s])); } } diff --git a/yarn-project/accounts/src/schnorr/account_contract.ts b/yarn-project/accounts/src/schnorr/account_contract.ts index 8e3f19c9154..aa651a073f1 100644 --- a/yarn-project/accounts/src/schnorr/account_contract.ts +++ b/yarn-project/accounts/src/schnorr/account_contract.ts @@ -30,9 +30,9 @@ export class SchnorrAccountContract extends DefaultAccountContract { class SchnorrAuthWitnessProvider implements AuthWitnessProvider { constructor(private signingPrivateKey: GrumpkinPrivateKey) {} - createAuthWit(message: Fr): Promise { + createAuthWit(messageHash: Fr): Promise { const schnorr = new Schnorr(); - const signature = schnorr.constructSignature(message.toBuffer(), this.signingPrivateKey).toBuffer(); - return Promise.resolve(new AuthWitness(message, [...signature])); + const signature = schnorr.constructSignature(messageHash.toBuffer(), this.signingPrivateKey).toBuffer(); + return Promise.resolve(new AuthWitness(messageHash, [...signature])); } } diff --git a/yarn-project/accounts/src/single_key/account_contract.ts b/yarn-project/accounts/src/single_key/account_contract.ts index c790340266f..1334c6791dc 100644 --- a/yarn-project/accounts/src/single_key/account_contract.ts +++ b/yarn-project/accounts/src/single_key/account_contract.ts @@ -35,11 +35,11 @@ export class SingleKeyAccountContract extends DefaultAccountContract { class SingleKeyAuthWitnessProvider implements AuthWitnessProvider { constructor(private privateKey: GrumpkinPrivateKey, private partialAddress: PartialAddress) {} - createAuthWit(message: Fr): Promise { + createAuthWit(messageHash: Fr): Promise { const schnorr = new Schnorr(); - const signature = schnorr.constructSignature(message.toBuffer(), this.privateKey); + const signature = schnorr.constructSignature(messageHash.toBuffer(), this.privateKey); const publicKey = generatePublicKey(this.privateKey); const witness = [...publicKey.toFields(), ...signature.toBuffer(), this.partialAddress]; - return Promise.resolve(new AuthWitness(message, witness)); + return Promise.resolve(new AuthWitness(messageHash, witness)); } } diff --git a/yarn-project/aztec.js/src/account/interface.ts b/yarn-project/aztec.js/src/account/interface.ts index 7da5226b749..5cbe13430bf 100644 --- a/yarn-project/aztec.js/src/account/interface.ts +++ b/yarn-project/aztec.js/src/account/interface.ts @@ -23,6 +23,8 @@ export interface AuthWitnessProvider { * If a message hash is provided, it will create a witness for that directly. * Otherwise, it will compute the message hash using the caller and the action of the intent. * @param messageHashOrIntent - The message hash or the intent (caller and action) to approve + * @param chainId - The chain id for the message, will default to the current chain id + * @param version - The version for the message, will default to the current protocol version * @returns The authentication witness */ createAuthWit( @@ -34,6 +36,10 @@ export interface AuthWitnessProvider { caller: AztecAddress; /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; + /** The chain id to approve */ + chainId?: Fr; + /** The version to approve */ + version?: Fr; }, ): Promise; } @@ -59,5 +65,11 @@ export interface AccountInterface extends AuthWitnessProvider, EntrypointInterfa /** Returns the address for this account. */ getAddress(): AztecAddress; + + /** Returns the chain id for this account */ + getChainId(): Fr; + + /** Returns the rollup version for this account */ + getVersion(): Fr; } // docs:end:account-interface diff --git a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts index 20be7695ccb..bc4c998ce7d 100644 --- a/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/private_fee_payment_method.ts @@ -58,11 +58,16 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { */ async getFunctionCalls(maxFee: Fr): Promise { const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash(this.paymentContract, { - args: [this.wallet.getCompleteAddress().address, this.paymentContract, maxFee, nonce], - functionData: new FunctionData(FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), true), - to: this.asset, - }); + const messageHash = computeAuthWitMessageHash( + this.paymentContract, + this.wallet.getChainId(), + this.wallet.getVersion(), + { + args: [this.wallet.getCompleteAddress().address, this.paymentContract, maxFee, nonce], + functionData: new FunctionData(FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), true), + to: this.asset, + }, + ); await this.wallet.createAuthWit(messageHash); const secretHashForRebate = computeMessageSecretHash(this.rebateSecret); diff --git a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts index bbc601d1505..ed44beb91eb 100644 --- a/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/public_fee_payment_method.ts @@ -51,14 +51,20 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { */ getFunctionCalls(maxFee: Fr): Promise { const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash(this.paymentContract, { - args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], - functionData: new FunctionData( - FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, - ), - to: this.asset, - }); + + const messageHash = computeAuthWitMessageHash( + this.paymentContract, + this.wallet.getChainId(), + this.wallet.getVersion(), + { + args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], + functionData: new FunctionData( + FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), + false, + ), + to: this.asset, + }, + ); return Promise.resolve([ this.wallet.setPublicAuthWit(messageHash, true).request(), diff --git a/yarn-project/aztec.js/src/utils/authwit.ts b/yarn-project/aztec.js/src/utils/authwit.ts index 2087730ca81..b7fd074d300 100644 --- a/yarn-project/aztec.js/src/utils/authwit.ts +++ b/yarn-project/aztec.js/src/utils/authwit.ts @@ -5,19 +5,23 @@ import { pedersenHash } from '@aztec/foundation/crypto'; // docs:start:authwit_computeAuthWitMessageHash /** * Compute an authentication witness message hash from a caller and a request - * H(target: AztecAddress, H(caller: AztecAddress, selector: Field, args_hash: Field)) + * H(target: AztecAddress, chainId: Field, version: Field, H(caller: AztecAddress, selector: Field, args_hash: Field)) * Example usage would be `bob` authenticating `alice` to perform a transfer of `10` * tokens from his account to herself: - * H(token, H(alice, transfer_selector, H(bob, alice, 10, nonce))) + * H(token, 1, 1, H(alice, transfer_selector, H(bob, alice, 10, nonce))) * `bob` then signs the message hash and gives it to `alice` who can then perform the * action. * @param caller - The caller approved to make the call + * @param chainId - The chain id for the message + * @param version - The version for the message * @param action - The request to be made (function call) * @returns The message hash for the witness */ -export const computeAuthWitMessageHash = (caller: AztecAddress, action: FunctionCall) => { +export const computeAuthWitMessageHash = (caller: AztecAddress, chainId: Fr, version: Fr, action: FunctionCall) => { return computeOuterAuthWitHash( action.to.toField(), + chainId, + version, computeInnerAuthWitHash([ caller.toField(), action.functionData.selector.toField(), @@ -51,12 +55,14 @@ export const computeInnerAuthWitHash = (args: Fr[]) => { * It is used as part of the `computeAuthWitMessageHash` but can also be used * in case the message is not a "call" to a function, but arbitrary data. * @param consumer - The address that can "consume" the authwit + * @param chainId - The chain id that can "consume" the authwit + * @param version - The version that can "consume" the authwit * @param innerHash - The inner hash for the witness * @returns The outer hash for the witness */ -export const computeOuterAuthWitHash = (consumer: AztecAddress, innerHash: Fr) => { +export const computeOuterAuthWitHash = (consumer: AztecAddress, chainId: Fr, version: Fr, innerHash: Fr) => { return pedersenHash( - [consumer.toField(), innerHash].map(fr => fr.toBuffer()), + [consumer.toField(), chainId, version, innerHash].map(fr => fr.toBuffer()), GeneratorIndex.AUTHWIT_OUTER, ); }; diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index 9c388f5b953..bc32d96c5ab 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -19,6 +19,14 @@ export class AccountWallet extends BaseWallet { return this.account.createTxExecutionRequest(execs, fee); } + getChainId(): Fr { + return this.account.getChainId(); + } + + getVersion(): Fr { + return this.account.getVersion(); + } + /** * Computes an authentication witness from either a message or a caller and an action. * If a message is provided, it will create a witness for the message directly. @@ -35,6 +43,10 @@ export class AccountWallet extends BaseWallet { caller: AztecAddress; /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; + /** The chain id to approve */ + chainId?: Fr; + /** The version to approve */ + version?: Fr; }, ): Promise { const messageHash = this.getMessageHash(messageHashOrIntent); @@ -59,6 +71,10 @@ export class AccountWallet extends BaseWallet { caller: AztecAddress; /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; + /** The chain id to approve */ + chainId?: Fr; + /** The version to approve */ + version?: Fr; }, authorized: boolean, ): ContractFunctionInteraction { @@ -84,16 +100,26 @@ export class AccountWallet extends BaseWallet { caller: AztecAddress; /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; + /** The chain id to approve */ + chainId?: Fr; + /** The version to approve */ + version?: Fr; }, ): Fr { if (Buffer.isBuffer(messageHashOrIntent)) { return Fr.fromBuffer(messageHashOrIntent); } else if (messageHashOrIntent instanceof Fr) { return messageHashOrIntent; - } else if (messageHashOrIntent.action instanceof ContractFunctionInteraction) { - return computeAuthWitMessageHash(messageHashOrIntent.caller, messageHashOrIntent.action.request()); + } else { + return computeAuthWitMessageHash( + messageHashOrIntent.caller, + messageHashOrIntent.chainId || this.getChainId(), + messageHashOrIntent.version || this.getVersion(), + messageHashOrIntent.action instanceof ContractFunctionInteraction + ? messageHashOrIntent.action.request() + : messageHashOrIntent.action, + ); } - return computeAuthWitMessageHash(messageHashOrIntent.caller, messageHashOrIntent.action); } /** @@ -113,6 +139,10 @@ export class AccountWallet extends BaseWallet { caller: AztecAddress; /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; + /** The chain id to approve */ + chainId?: Fr; + /** The version to approve */ + version?: Fr; }, ): Promise<{ /** boolean flag indicating if the authwit is valid in private context */ @@ -148,6 +178,10 @@ export class AccountWallet extends BaseWallet { caller: AztecAddress; /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; + /** The chain id to approve */ + chainId?: Fr; + /** The version to approve */ + version?: Fr; }, ): ContractFunctionInteraction { const message = this.getMessageHash(messageHashOrIntent); diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 6ce1d9fa34d..759e9180093 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -31,6 +31,10 @@ export abstract class BaseWallet implements Wallet { abstract getCompleteAddress(): CompleteAddress; + abstract getChainId(): Fr; + + abstract getVersion(): Fr; + abstract createTxExecutionRequest(execs: FunctionCall[], fee?: FeeOptions): Promise; abstract createAuthWit( @@ -42,6 +46,10 @@ export abstract class BaseWallet implements Wallet { caller: AztecAddress; /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; + /** The chain id to approve */ + chainId?: Fr; + /** The version to approve */ + version?: Fr; }, ): Promise; diff --git a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts index e99e383a757..e49febbd4e6 100644 --- a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts @@ -27,11 +27,19 @@ export class SignerlessWallet extends BaseWallet { ); } + getChainId(): Fr { + throw new Error('Method not implemented.'); + } + + getVersion(): Fr { + throw new Error('Method not implemented.'); + } + getCompleteAddress(): CompleteAddress { throw new Error('Method not implemented.'); } - createAuthWit(_message: Fr): Promise { + createAuthWit(_messageHash: Fr): Promise { throw new Error('Method not implemented.'); } } diff --git a/yarn-project/end-to-end/src/e2e_authwit.test.ts b/yarn-project/end-to-end/src/e2e_authwit.test.ts index d8487288bef..09e4acf53fe 100644 --- a/yarn-project/end-to-end/src/e2e_authwit.test.ts +++ b/yarn-project/end-to-end/src/e2e_authwit.test.ts @@ -13,16 +13,23 @@ describe('e2e_authwit_tests', () => { let wallets: AccountWallet[]; let accounts: CompleteAddress[]; + let chainId: Fr; + let version: Fr; + beforeAll(async () => { ({ wallets, accounts } = await setup(2)); await publicDeployAccounts(wallets[0], accounts.slice(0, 2)); + + const nodeInfo = await wallets[0].getNodeInfo(); + chainId = new Fr(nodeInfo.chainId); + version = new Fr(nodeInfo.protocolVersion); }, 100_000); describe('Private', () => { describe('arbitrary data', () => { it('happy path', async () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead')]); - const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); + const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, version, innerHash); const witness = await wallets[0].createAuthWit(outerHash); await wallets[1].addAuthWitness(witness); @@ -51,7 +58,7 @@ describe('e2e_authwit_tests', () => { describe('failure case', () => { it('cancel before usage', async () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0xbeef')]); - const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); + const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, version, innerHash); expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ isValidInPrivate: false, @@ -82,6 +89,94 @@ describe('e2e_authwit_tests', () => { // The transaction should be dropped because of a cancelled authwit (duplicate nullifier) await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); }); + + it('invalid chain id', async () => { + const invalidChainId = Fr.random(); + + const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0xbeef')]); + const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), invalidChainId, version, innerHash); + const outerCorrectHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, version, innerHash); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerCorrectHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + const witness = await wallets[0].createAuthWit(outerHash); + await wallets[1].addAuthWitness(witness); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: true, + isValidInPublic: false, + }); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerCorrectHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); + const txCancelledAuthwit = c.withWallet(wallets[1]).methods.spend_private_authwit(innerHash).send(); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: true, + isValidInPublic: false, + }); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerCorrectHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + // The transaction should be dropped because of the invalid chain id + await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); + }); + + it('invalid version', async () => { + const invalidVersion = Fr.random(); + + const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0xbeef')]); + const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, invalidVersion, innerHash); + const outerCorrectHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, version, innerHash); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerCorrectHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + const witness = await wallets[0].createAuthWit(outerHash); + await wallets[1].addAuthWitness(witness); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: true, + isValidInPublic: false, + }); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerCorrectHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); + const txCancelledAuthwit = c.withWallet(wallets[1]).methods.spend_private_authwit(innerHash).send(); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: true, + isValidInPublic: false, + }); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerCorrectHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + + // The transaction should be dropped because of the invalid version + await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); + }); }); }); }); @@ -90,7 +185,7 @@ describe('e2e_authwit_tests', () => { describe('arbitrary data', () => { it('happy path', async () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x01')]); - const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); + const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, version, innerHash); expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ isValidInPrivate: false, @@ -116,7 +211,7 @@ describe('e2e_authwit_tests', () => { describe('failure case', () => { it('cancel before usage', async () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x02')]); - const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); + const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), chainId, version, innerHash); expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ isValidInPrivate: false, diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts index efb35e65902..4fbf7bacd4f 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts @@ -740,7 +740,12 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); + const messageHash = computeAuthWitMessageHash( + accounts[1].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), ); @@ -763,7 +768,12 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); + const expectedMessageHash = computeAuthWitMessageHash( + accounts[2].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); @@ -1047,7 +1057,12 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); + const expectedMessageHash = computeAuthWitMessageHash( + accounts[2].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. @@ -1282,7 +1297,12 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); + const messageHash = computeAuthWitMessageHash( + accounts[1].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${messageHash.toString()}`, @@ -1300,7 +1320,12 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); const action = asset.withWallet(wallets[2]).methods.burn(accounts[0].address, amount, nonce); - const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); + const expectedMessageHash = computeAuthWitMessageHash( + accounts[2].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); 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 5fb8ee541c8..d337897f3bd 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 @@ -205,6 +205,8 @@ describe('e2e_cross_chain_messaging', () => { const nonce = Fr.random(); const expectedBurnMessageHash = computeAuthWitMessageHash( l2Bridge.address, + user1Wallet.getChainId(), + user1Wallet.getVersion(), l2Token.methods.burn(user1Wallet.getAddress(), withdrawAmount, nonce).request(), ); // Should fail as owner has not given approval to bridge burn their funds. diff --git a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts index 1f2bd159972..eaa666f525c 100644 --- a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts +++ b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts @@ -9,7 +9,6 @@ import { Note, PXE, TxHash, - computeAuthWitMessageHash, computeMessageSecretHash, generatePublicKey, } from '@aztec/aztec.js'; @@ -264,8 +263,7 @@ describe('e2e_crowdfunding_and_claim', () => { const action = donationToken .withWallet(donorWallets[1]) .methods.transfer(donorWallets[1].getAddress(), crowdfundingContract.address, donationAmount, 0); - const messageHash = computeAuthWitMessageHash(crowdfundingContract.address, action.request()); - const witness = await donorWallets[1].createAuthWit(messageHash); + const witness = await donorWallets[1].createAuthWit({ caller: crowdfundingContract.address, action }); await donorWallets[1].addAuthWitness(witness); } diff --git a/yarn-project/end-to-end/src/e2e_fees.test.ts b/yarn-project/end-to-end/src/e2e_fees.test.ts index 0d87a44df87..9dbbc4825e9 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -687,14 +687,19 @@ describe('e2e_fees', () => { class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { getFunctionCalls(maxFee: Fr): Promise { const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash(this.paymentContract, { - args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], - functionData: new FunctionData( - FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, - ), - to: this.asset, - }); + const messageHash = computeAuthWitMessageHash( + this.paymentContract, + this.wallet.getChainId(), + this.wallet.getVersion(), + { + args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], + functionData: new FunctionData( + FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), + false, + ), + to: this.asset, + }, + ); const tooMuchFee = new Fr(maxFee.toBigInt() * 2n); @@ -716,14 +721,19 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { async getFunctionCalls(maxFee: Fr): Promise { // authorize the FPC to take the max fee from Alice const nonce = Fr.random(); - const messageHash1 = computeAuthWitMessageHash(this.paymentContract, { - args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], - functionData: new FunctionData( - FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), - false, - ), - to: this.asset, - }); + const messageHash1 = computeAuthWitMessageHash( + this.paymentContract, + this.wallet.getChainId(), + this.wallet.getVersion(), + { + args: [this.wallet.getAddress(), this.paymentContract, maxFee, nonce], + functionData: new FunctionData( + FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), + false, + ), + to: this.asset, + }, + ); // authorize the FPC to take the maxFee // do this first because we only get 2 feepayload calls diff --git a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts index 1a29f947882..b349bfb39c3 100644 --- a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts @@ -328,6 +328,8 @@ describe('e2e_lending_contract', () => { const nonce = Fr.random(); const messageHash = computeAuthWitMessageHash( lendingContract.address, + wallet.getChainId(), + wallet.getVersion(), stableCoin.methods.burn_public(lendingAccount.address, repayAmount, nonce).request(), ); 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 d9561fee104..581e2e603c4 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 @@ -108,6 +108,8 @@ describe('e2e_public_cross_chain_messaging', () => { const nonce = Fr.random(); const burnMessageHash = computeAuthWitMessageHash( l2Bridge.address, + wallets[0].getChainId(), + wallets[0].getVersion(), l2Token.methods.burn_public(ownerAddress, withdrawAmount, nonce).request(), ); await user1Wallet.setPublicAuthWit(burnMessageHash, true).send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_token_contract.test.ts index f7e60748f2e..d1f01897e01 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract.test.ts @@ -513,7 +513,12 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); + const messageHash = computeAuthWitMessageHash( + accounts[1].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); await wallets[0].setPublicAuthWit(messageHash, true).send().wait(); @@ -574,7 +579,6 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved // docs:start:authwit_transfer_example - // docs:start:authwit_computeAuthWitMessageHash const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); @@ -661,7 +665,12 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); + const messageHash = computeAuthWitMessageHash( + accounts[1].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${messageHash.toString()}`, @@ -678,7 +687,12 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); + const expectedMessageHash = computeAuthWitMessageHash( + accounts[2].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); @@ -955,7 +969,12 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); + const expectedMessageHash = computeAuthWitMessageHash( + accounts[2].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); // Both wallets are connected to same node and PXE so we could just insert directly // But doing it in two actions to show the flow. @@ -1133,7 +1152,12 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); + const messageHash = computeAuthWitMessageHash( + accounts[1].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${messageHash.toString()}`, @@ -1148,7 +1172,12 @@ describe('e2e_token_contract', () => { // We need to compute the message we want to sign and add it to the wallet as approved const action = asset.withWallet(wallets[2]).methods.burn(accounts[0].address, amount, nonce); - const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); + const expectedMessageHash = computeAuthWitMessageHash( + accounts[2].address, + wallets[0].getChainId(), + wallets[0].getVersion(), + action.request(), + ); const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); diff --git a/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts b/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts index 5501c8d9875..604f5edf920 100644 --- a/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts +++ b/yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts @@ -34,10 +34,10 @@ class SchnorrHardcodedKeyAccountContract extends DefaultAccountContract { getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider { const privateKey = this.privateKey; return { - createAuthWit(message: Fr): Promise { + createAuthWit(messageHash: Fr): Promise { const signer = new Schnorr(); - const signature = signer.constructSignature(message.toBuffer(), privateKey); - return Promise.resolve(new AuthWitness(message, [...signature.toBuffer()])); + const signature = signer.constructSignature(messageHash.toBuffer(), privateKey); + return Promise.resolve(new AuthWitness(messageHash, [...signature.toBuffer()])); }, }; } 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 dd60e379ea6..7f4aed845eb 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 @@ -439,6 +439,8 @@ export const uniswapL1L2TestSuite = ( const nonceForWETHTransferApproval = new Fr(1n); const transferMessageHash = computeAuthWitMessageHash( uniswapL2Contract.address, + ownerWallet.getChainId(), + ownerWallet.getVersion(), wethCrossChainHarness.l2Token.methods .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), @@ -470,7 +472,12 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress, nonceForSwap, ); - const swapMessageHash = computeAuthWitMessageHash(sponsorAddress, action.request()); + const swapMessageHash = computeAuthWitMessageHash( + sponsorAddress, + ownerWallet.getChainId(), + ownerWallet.getVersion(), + action.request(), + ); await ownerWallet.setPublicAuthWit(swapMessageHash, true).send().wait(); // 4.2 Call swap_public from user2 on behalf of owner @@ -636,6 +643,9 @@ export const uniswapL1L2TestSuite = ( const expectedMessageHash = computeAuthWitMessageHash( uniswapL2Contract.address, + ownerWallet.getChainId(), + ownerWallet.getVersion(), + wethCrossChainHarness.l2Token.methods .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) .request(), @@ -709,6 +719,9 @@ export const uniswapL1L2TestSuite = ( const nonceForWETHTransferApproval = new Fr(2n); const transferMessageHash = computeAuthWitMessageHash( uniswapL2Contract.address, + ownerWallet.getChainId(), + ownerWallet.getVersion(), + wethCrossChainHarness.l2Token.methods .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), @@ -760,7 +773,12 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress, nonceForSwap, ); - const swapMessageHash = computeAuthWitMessageHash(approvedUser, action.request()); + const swapMessageHash = computeAuthWitMessageHash( + approvedUser, + ownerWallet.getChainId(), + ownerWallet.getVersion(), + action.request(), + ); await ownerWallet.setPublicAuthWit(swapMessageHash, true).send().wait(); // Swap! @@ -775,6 +793,8 @@ export const uniswapL1L2TestSuite = ( const transferMessageHash = computeAuthWitMessageHash( uniswapL2Contract.address, + ownerWallet.getChainId(), + ownerWallet.getVersion(), wethCrossChainHarness.l2Token.methods .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), @@ -955,6 +975,8 @@ export const uniswapL1L2TestSuite = ( const nonceForWETHTransferApproval = new Fr(5n); const transferMessageHash = computeAuthWitMessageHash( uniswapL2Contract.address, + ownerWallet.getChainId(), + ownerWallet.getVersion(), wethCrossChainHarness.l2Token.methods .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index 877ba2a4a3d..0cb82b372b2 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -32,7 +32,12 @@ export class DefaultDappEntrypoint implements EntrypointInterface { const functionData = FunctionData.fromAbi(abi); const innerHash = computeInnerAuthWitHash([Fr.ZERO, functionData.selector.toField(), entrypointPackedArgs.hash]); - const outerHash = computeOuterAuthWitHash(this.dappEntrypointAddress, innerHash); + const outerHash = computeOuterAuthWitHash( + this.dappEntrypointAddress, + new Fr(this.chainId), + new Fr(this.version), + innerHash, + ); const authWitness = await this.userAuthWitnessProvider.createAuthWit(outerHash); From a9d22ff0bb727345a3b81b1542690a63f2087a4b Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:15:21 +0000 Subject: [PATCH 23/36] chore: skip slither in docker (#5384) Skipping slither runs in the docker for less pain with the changes happening all the time. --- l1-contracts/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/l1-contracts/Dockerfile b/l1-contracts/Dockerfile index bb8cefde32c..e5349824677 100644 --- a/l1-contracts/Dockerfile +++ b/l1-contracts/Dockerfile @@ -4,8 +4,8 @@ FROM ubuntu:lunar RUN apt update && apt install curl git jq bash nodejs npm python3.11-full python3-pip -y # Use virtualenv, do not try to use pipx, it's not working. -RUN python3 -m venv /root/.venv -RUN /root/.venv/bin/pip3 install slither-analyzer==0.10.0 slitherin==0.5.0 +# RUN python3 -m venv /root/.venv +# RUN /root/.venv/bin/pip3 install slither-analyzer==0.10.0 slitherin==0.5.0 RUN curl -L https://foundry.paradigm.xyz | bash # Set env variables for foundry and venv @@ -20,7 +20,7 @@ RUN forge clean && forge fmt --check && forge build && forge test --no-match-con RUN npm install --global yarn RUN yarn && yarn lint -RUN git add . && yarn slither && yarn slither-has-diff +# RUN git add . && yarn slither && yarn slither-has-diff RUN forge build FROM scratch From 9ea8186c88d9355159487b4c234c60a88c4bdaaf Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:37:20 +0000 Subject: [PATCH 24/36] feat: Dynamic proving (#5346) This PR introduces a new proving orhestration system enabling a block to be proven concurrently with simulation. It also creates the `prover-client` package and moves some of the proving functionality to this package from `sequencer-client`. --- .../sandbox/references/sandbox-reference.md | 2 +- yarn-project/aztec-node/package.json | 2 + .../aztec-node/src/aztec-node/config.ts | 6 +- .../aztec-node/src/aztec-node/server.ts | 27 +- .../src/aztec-node/simulator-factory.ts | 24 + yarn-project/aztec-node/terraform/main.tf | 2 +- yarn-project/aztec-node/tsconfig.json | 6 + yarn-project/aztec/src/cli/cli.ts | 1 + yarn-project/aztec/src/cli/cmds/start_node.ts | 4 + yarn-project/aztec/src/cli/texts.ts | 7 + yarn-project/circuit-types/src/body.ts | 4 + .../src/interfaces/block-prover.ts | 41 + .../circuit-types/src/interfaces/index.ts | 2 + .../src/interfaces/prover-client.ts | 11 + yarn-project/circuit-types/src/l2_block.ts | 12 + yarn-project/circuit-types/src/tx/index.ts | 1 + .../src/tx}/processed_tx.ts | 0 yarn-project/circuit-types/src/tx_effect.ts | 12 + yarn-project/circuits.js/package.json | 3 +- yarn-project/circuits.js/src/structs/proof.ts | 4 +- yarn-project/end-to-end/package.json | 3 + .../src/integration_l1_publisher.test.ts | 70 +- yarn-project/end-to-end/tsconfig.json | 6 + yarn-project/prover-client/package.json | 9 + yarn-project/prover-client/src/config.ts | 22 + .../prover-client/src/dummy-prover.ts | 45 + yarn-project/prover-client/src/index.ts | 12 +- .../src/mocks/verification_keys.ts | 0 .../orchestrator/block-building-helpers.ts | 595 +++++++++++++ .../src/orchestrator/orchestrator.test.ts | 596 +++++++++++++ .../src/orchestrator/orchestrator.ts | 522 +++++++++++ .../src/orchestrator/proving-state.ts | 182 ++++ .../src/prover/empty.ts | 0 .../src/prover/index.ts | 0 .../src/simulator/rollup.ts | 39 +- .../prover-client/src/tx-prover/tx-prover.ts | 73 ++ yarn-project/prover-client/tsconfig.json | 18 + .../src/block_builder/index.ts | 20 - .../block_builder/solo_block_builder.test.ts | 453 ---------- .../src/block_builder/solo_block_builder.ts | 812 ------------------ .../src/block_builder/types.ts | 8 - .../src/client/sequencer-client.ts | 49 +- yarn-project/sequencer-client/src/index.ts | 9 - .../src/sequencer/abstract_phase_manager.ts | 14 +- .../src/sequencer/app_logic_phase_manager.ts | 4 +- .../src/sequencer/phase_manager_factory.ts | 9 - .../src/sequencer/public_processor.test.ts | 13 +- .../src/sequencer/public_processor.ts | 29 +- .../src/sequencer/sequencer.test.ts | 89 +- .../src/sequencer/sequencer.ts | 25 +- .../src/sequencer/setup_phase_manager.test.ts | 11 - .../src/sequencer/setup_phase_manager.ts | 4 +- .../src/sequencer/tail_phase_manager.ts | 4 +- .../src/sequencer/teardown_phase_manager.ts | 4 +- .../src/sequencer/tx_validator.ts | 3 +- .../sequencer-client/src/simulator/index.ts | 45 - .../src/simulator/public_kernel.ts | 4 +- yarn-project/simulator/package.json | 1 + yarn-project/simulator/src/index.ts | 1 + .../src/simulator/acvm_native.ts | 0 .../src/simulator/acvm_wasm.ts | 0 yarn-project/simulator/src/simulator/index.ts | 3 + .../src/simulator/simulation_provider.ts | 0 yarn-project/yarn.lock | 17 +- 64 files changed, 2459 insertions(+), 1535 deletions(-) create mode 100644 yarn-project/aztec-node/src/aztec-node/simulator-factory.ts create mode 100644 yarn-project/circuit-types/src/interfaces/block-prover.ts create mode 100644 yarn-project/circuit-types/src/interfaces/prover-client.ts rename yarn-project/{sequencer-client/src/sequencer => circuit-types/src/tx}/processed_tx.ts (100%) create mode 100644 yarn-project/prover-client/src/config.ts create mode 100644 yarn-project/prover-client/src/dummy-prover.ts rename yarn-project/{sequencer-client => prover-client}/src/mocks/verification_keys.ts (100%) create mode 100644 yarn-project/prover-client/src/orchestrator/block-building-helpers.ts create mode 100644 yarn-project/prover-client/src/orchestrator/orchestrator.test.ts create mode 100644 yarn-project/prover-client/src/orchestrator/orchestrator.ts create mode 100644 yarn-project/prover-client/src/orchestrator/proving-state.ts rename yarn-project/{sequencer-client => prover-client}/src/prover/empty.ts (100%) rename yarn-project/{sequencer-client => prover-client}/src/prover/index.ts (100%) rename yarn-project/{sequencer-client => prover-client}/src/simulator/rollup.ts (75%) create mode 100644 yarn-project/prover-client/src/tx-prover/tx-prover.ts delete mode 100644 yarn-project/sequencer-client/src/block_builder/index.ts delete mode 100644 yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts delete mode 100644 yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts delete mode 100644 yarn-project/sequencer-client/src/block_builder/types.ts rename yarn-project/{sequencer-client => simulator}/src/simulator/acvm_native.ts (100%) rename yarn-project/{sequencer-client => simulator}/src/simulator/acvm_wasm.ts (100%) create mode 100644 yarn-project/simulator/src/simulator/index.ts rename yarn-project/{sequencer-client => simulator}/src/simulator/simulation_provider.ts (100%) diff --git a/docs/docs/developers/sandbox/references/sandbox-reference.md b/docs/docs/developers/sandbox/references/sandbox-reference.md index 408572796eb..c454b16f9b9 100644 --- a/docs/docs/developers/sandbox/references/sandbox-reference.md +++ b/docs/docs/developers/sandbox/references/sandbox-reference.md @@ -59,7 +59,7 @@ cd ~/.aztec && docker-compose up If you wish to run components of the Aztec network stack separately, you can use the `aztec start` command with various options for enabling components. ```bash -aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] ----p2p-bootstrap [p2pOptions] +aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] --prover [proverOptions] ----p2p-bootstrap [p2pOptions] ``` Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node. If you want to e.g. run a PXE separately to a node, you can: diff --git a/yarn-project/aztec-node/package.json b/yarn-project/aztec-node/package.json index 2c0dd26296c..f49c5c58920 100644 --- a/yarn-project/aztec-node/package.json +++ b/yarn-project/aztec-node/package.json @@ -42,7 +42,9 @@ "@aztec/l1-artifacts": "workspace:^", "@aztec/merkle-tree": "workspace:^", "@aztec/p2p": "workspace:^", + "@aztec/prover-client": "workspace:^", "@aztec/sequencer-client": "workspace:^", + "@aztec/simulator": "workspace:^", "@aztec/types": "workspace:^", "@aztec/world-state": "workspace:^", "koa": "^2.14.2", diff --git a/yarn-project/aztec-node/src/aztec-node/config.ts b/yarn-project/aztec-node/src/aztec-node/config.ts index 73f14115804..07f79f82383 100644 --- a/yarn-project/aztec-node/src/aztec-node/config.ts +++ b/yarn-project/aztec-node/src/aztec-node/config.ts @@ -12,6 +12,9 @@ export type AztecNodeConfig = ArchiverConfig & /** Whether the sequencer is disabled for this node. */ disableSequencer: boolean; + /** Whether the prover is disabled for this node. */ + disableProver: boolean; + /** A URL for an archiver service that the node will use. */ archiverUrl?: string; }; @@ -21,13 +24,14 @@ export type AztecNodeConfig = ArchiverConfig & * @returns A valid aztec node config. */ export function getConfigEnvVars(): AztecNodeConfig { - const { SEQ_DISABLED } = process.env; + const { SEQ_DISABLED, PROVER_DISABLED } = process.env; const allEnvVars: AztecNodeConfig = { ...getSequencerVars(), ...getArchiverVars(), ...getP2PConfigEnvVars(), ...getWorldStateVars(), disableSequencer: !!SEQ_DISABLED, + disableProver: !!PROVER_DISABLED, archiverUrl: process.env.ARCHIVER_URL, }; diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 46f9aef2146..43a1aefd8bc 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -12,6 +12,7 @@ import { LogType, MerkleTreeId, NullifierMembershipWitness, + ProverClient, PublicDataWitness, SequencerConfig, SiblingPath, @@ -20,6 +21,7 @@ import { TxHash, TxReceipt, TxStatus, + partitionReverts, } from '@aztec/circuit-types'; import { ARCHIVE_HEIGHT, @@ -44,14 +46,14 @@ import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; import { initStoreForRollup, openTmpStore } from '@aztec/kv-store/utils'; import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; import { AztecKVTxPool, P2P, createP2PClient } from '@aztec/p2p'; +import { DummyProver, TxProver } from '@aztec/prover-client'; import { GlobalVariableBuilder, PublicProcessorFactory, SequencerClient, - WASMSimulator, getGlobalVariableBuilder, - partitionReverts, } from '@aztec/sequencer-client'; +import { WASMSimulator } from '@aztec/simulator'; import { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { MerkleTrees, @@ -62,6 +64,7 @@ import { } from '@aztec/world-state'; import { AztecNodeConfig } from './config.js'; +import { getSimulationProvider } from './simulator-factory.js'; /** * The aztec node. @@ -81,6 +84,7 @@ export class AztecNodeService implements AztecNode { protected readonly version: number, protected readonly globalVariableBuilder: GlobalVariableBuilder, protected readonly merkleTreesDb: AztecKVStore, + private readonly prover: ProverClient, private log = createDebugLogger('aztec:node'), ) { const message = @@ -139,10 +143,25 @@ export class AztecNodeService implements AztecNode { // start both and wait for them to sync from the block source await Promise.all([p2pClient.start(), worldStateSynchronizer.start()]); + // start the prover if we have been told to + const simulationProvider = await getSimulationProvider(config, log); + const prover = config.disableProver + ? await DummyProver.new() + : await TxProver.new(config, worldStateSynchronizer, simulationProvider); + // now create the sequencer const sequencer = config.disableSequencer ? undefined - : await SequencerClient.new(config, p2pClient, worldStateSynchronizer, archiver, archiver, archiver); + : await SequencerClient.new( + config, + p2pClient, + worldStateSynchronizer, + archiver, + archiver, + archiver, + prover, + simulationProvider, + ); return new AztecNodeService( config, @@ -158,6 +177,7 @@ export class AztecNodeService implements AztecNode { config.version, getGlobalVariableBuilder(config), store, + prover, log, ); } @@ -299,6 +319,7 @@ export class AztecNodeService implements AztecNode { await this.p2pClient.stop(); await this.worldStateSynchronizer.stop(); await this.blockSource.stop(); + await this.prover.stop(); this.log.info(`Stopped`); } diff --git a/yarn-project/aztec-node/src/aztec-node/simulator-factory.ts b/yarn-project/aztec-node/src/aztec-node/simulator-factory.ts new file mode 100644 index 00000000000..8cf8de0b01f --- /dev/null +++ b/yarn-project/aztec-node/src/aztec-node/simulator-factory.ts @@ -0,0 +1,24 @@ +import { DebugLogger } from '@aztec/foundation/log'; +import { NativeACVMSimulator, SimulationProvider, WASMSimulator } from '@aztec/simulator'; + +import * as fs from 'fs/promises'; + +import { AztecNodeConfig } from './config.js'; + +export async function getSimulationProvider( + config: AztecNodeConfig, + logger?: DebugLogger, +): Promise { + if (config.acvmBinaryPath && config.acvmWorkingDirectory) { + try { + await fs.access(config.acvmBinaryPath, fs.constants.R_OK); + await fs.mkdir(config.acvmWorkingDirectory, { recursive: true }); + logger?.(`Using native ACVM at ${config.acvmBinaryPath} and working directory ${config.acvmWorkingDirectory}`); + return new NativeACVMSimulator(config.acvmWorkingDirectory, config.acvmBinaryPath); + } catch { + logger?.(`Failed to access ACVM at ${config.acvmBinaryPath}, falling back to WASM`); + } + } + logger?.('Using WASM ACVM simulation'); + return new WASMSimulator(); +} diff --git a/yarn-project/aztec-node/terraform/main.tf b/yarn-project/aztec-node/terraform/main.tf index 5bf9187d744..fffdb2991aa 100644 --- a/yarn-project/aztec-node/terraform/main.tf +++ b/yarn-project/aztec-node/terraform/main.tf @@ -155,7 +155,7 @@ resource "aws_ecs_task_definition" "aztec-node" { { "name": "${var.DEPLOY_TAG}-aztec-node-${count.index + 1}", "image": "${var.DOCKERHUB_ACCOUNT}/aztec:${var.DEPLOY_TAG}", - "command": ["start", "--node", "--archiver", "--sequencer"], + "command": ["start", "--node", "--archiver", "--sequencer", "--prover"], "essential": true, "memoryReservation": 3776, "portMappings": [ diff --git a/yarn-project/aztec-node/tsconfig.json b/yarn-project/aztec-node/tsconfig.json index 9979b01f137..811c082824f 100644 --- a/yarn-project/aztec-node/tsconfig.json +++ b/yarn-project/aztec-node/tsconfig.json @@ -33,9 +33,15 @@ { "path": "../p2p" }, + { + "path": "../prover-client" + }, { "path": "../sequencer-client" }, + { + "path": "../simulator" + }, { "path": "../types" }, diff --git a/yarn-project/aztec/src/cli/cli.ts b/yarn-project/aztec/src/cli/cli.ts index a6ad675c617..a373f6e97ba 100644 --- a/yarn-project/aztec/src/cli/cli.ts +++ b/yarn-project/aztec/src/cli/cli.ts @@ -36,6 +36,7 @@ export function getProgram(userLog: LogFn, debugLogger: DebugLogger): Command { .option('-px, --pxe [options]', cliTexts.pxe) .option('-a, --archiver [options]', cliTexts.archiver) .option('-s, --sequencer [options]', cliTexts.sequencer) + .option('-r, --prover [options]', cliTexts.prover) .option('-p2p, --p2p-bootstrap [options]', cliTexts.p2pBootstrap) .action(async options => { // list of 'stop' functions to call when process ends diff --git a/yarn-project/aztec/src/cli/cmds/start_node.ts b/yarn-project/aztec/src/cli/cmds/start_node.ts index 04e066a39ab..f498b42fdef 100644 --- a/yarn-project/aztec/src/cli/cmds/start_node.ts +++ b/yarn-project/aztec/src/cli/cmds/start_node.ts @@ -59,6 +59,10 @@ export const startNode = async ( nodeConfig.publisherPrivateKey = `0x${Buffer.from(privKey!).toString('hex')}`; } + if (!options.prover) { + nodeConfig.disableProver = true; + } + // Create and start Aztec Node. const node = await createAztecNode(nodeConfig); const nodeServer = createAztecNodeRpcServer(node); diff --git a/yarn-project/aztec/src/cli/texts.ts b/yarn-project/aztec/src/cli/texts.ts index 4c37b30ff9a..0ee661350c3 100644 --- a/yarn-project/aztec/src/cli/texts.ts +++ b/yarn-project/aztec/src/cli/texts.ts @@ -63,7 +63,14 @@ export const cliTexts = { 'requiredConfirmations:SEQ_REQUIRED_CONFIRMATIONS - number - The number of confirmations required before publishing a block. Default: 1\n' + 'l1BlockPublishRetryIntervalMS:SEQ_PUBLISH_RETRY_INTERVAL_MS - number - The interval in ms to wait before retrying to publish a block. Default: 1000\n' + 'transactionPollingIntervalMS:SEQ_TX_POLLING_INTERVAL_MS - number - The interval in ms to wait before polling for new transactions. Default: 1000\n' + + 'acvmBinaryPath:ACVM_BINARY_PATH - string - The full path to an instance of the acvm cli application. If not provided will fallback to WASM circuit simulation\n' + + 'acvmWorkingDirectory:ACVM_WORKING_DIRECTORY - string - A directory to use for temporary files used by the acvm application. If not provided WASM circuit simulation will be used\n' + contractAddresses, + prover: + 'Starts a Prover with options. If started additionally to --node, the Prover will attach to that node.\n' + + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + + 'acvmBinaryPath:ACVM_BINARY_PATH - string - The full path to an instance of the acvm cli application. If not provided will fallback to WASM circuit simulation\n' + + 'acvmWorkingDirectory:ACVM_WORKING_DIRECTORY - string - A directory to use for temporary files used by the acvm application. If not provided WASM circuit simulation will be used\n', p2pBootstrap: 'Starts a P2P bootstrap node with options.\n' + 'Available options are listed below as cliProperty:ENV_VARIABLE_NAME.\n' + diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index fcabae1c013..79b794a9697 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -95,4 +95,8 @@ export class Body { return new Body(txEffects); } + + static empty() { + return new Body([]); + } } diff --git a/yarn-project/circuit-types/src/interfaces/block-prover.ts b/yarn-project/circuit-types/src/interfaces/block-prover.ts new file mode 100644 index 00000000000..9e02a117b22 --- /dev/null +++ b/yarn-project/circuit-types/src/interfaces/block-prover.ts @@ -0,0 +1,41 @@ +import { Fr, GlobalVariables, Proof } from '@aztec/circuits.js'; + +import { L2Block } from '../l2_block.js'; +import { ProcessedTx } from '../tx/processed_tx.js'; + +export enum PROVING_STATUS { + SUCCESS, + FAILURE, +} + +export type ProvingSuccess = { + status: PROVING_STATUS.SUCCESS; + block: L2Block; + proof: Proof; +}; + +export type ProvingFailure = { + status: PROVING_STATUS.FAILURE; + reason: string; +}; + +export type ProvingResult = ProvingSuccess | ProvingFailure; + +export type ProvingTicket = { + provingPromise: Promise; +}; + +/** + * The interface to the block prover. + * Provides the ability to generate proofs and build rollups. + */ +export interface BlockProver { + startNewBlock( + numTxs: number, + globalVariables: GlobalVariables, + l1ToL2Messages: Fr[], + emptyTx: ProcessedTx, + ): Promise; + + addNewTx(tx: ProcessedTx): Promise; +} diff --git a/yarn-project/circuit-types/src/interfaces/index.ts b/yarn-project/circuit-types/src/interfaces/index.ts index 8997ca87955..25d6f63bd82 100644 --- a/yarn-project/circuit-types/src/interfaces/index.ts +++ b/yarn-project/circuit-types/src/interfaces/index.ts @@ -5,3 +5,5 @@ export * from './sync-status.js'; export * from './configs.js'; export * from './nullifier_tree.js'; export * from './public_data_tree.js'; +export * from './prover-client.js'; +export * from './block-prover.js'; diff --git a/yarn-project/circuit-types/src/interfaces/prover-client.ts b/yarn-project/circuit-types/src/interfaces/prover-client.ts new file mode 100644 index 00000000000..ac803d0e94b --- /dev/null +++ b/yarn-project/circuit-types/src/interfaces/prover-client.ts @@ -0,0 +1,11 @@ +import { BlockProver } from './block-prover.js'; + +/** + * The interface to the prover client. + * Provides the ability to generate proofs and build rollups. + */ +export interface ProverClient extends BlockProver { + start(): Promise; + + stop(): Promise; +} diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index b8535432dfd..e02ea43329b 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -114,6 +114,18 @@ export class L2Block { }); } + /** + * Creates an L2 block containing empty data. + * @returns The L2 block. + */ + static empty(): L2Block { + return L2Block.fromFields({ + archive: AppendOnlyTreeSnapshot.zero(), + header: Header.empty(), + body: Body.empty(), + }); + } + get number(): number { return Number(this.header.globalVariables.blockNumber.toBigInt()); } diff --git a/yarn-project/circuit-types/src/tx/index.ts b/yarn-project/circuit-types/src/tx/index.ts index 12409f062b8..f1ca9d6f805 100644 --- a/yarn-project/circuit-types/src/tx/index.ts +++ b/yarn-project/circuit-types/src/tx/index.ts @@ -1,3 +1,4 @@ export * from './tx.js'; export * from './tx_hash.js'; export * from './tx_receipt.js'; +export * from './processed_tx.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts similarity index 100% rename from yarn-project/sequencer-client/src/sequencer/processed_tx.ts rename to yarn-project/circuit-types/src/tx/processed_tx.ts diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index cf51aca0ed1..c80d0cee28d 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -142,6 +142,18 @@ export class TxEffect { ); } + static empty(): TxEffect { + return new TxEffect( + RevertCode.OK, + makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, Fr.zero), + makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero), + makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), + makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite.empty), + TxL2Logs.empty(), + TxL2Logs.empty(), + ); + } + /** * Returns a string representation of the TxEffect object. */ diff --git a/yarn-project/circuits.js/package.json b/yarn-project/circuits.js/package.json index f6192beede0..4584f83c848 100644 --- a/yarn-project/circuits.js/package.json +++ b/yarn-project/circuits.js/package.json @@ -11,7 +11,8 @@ "./types": "./dest/types/index.js", "./constants": "./dest/constants.gen.js", "./contract": "./dest/contract/index.js", - "./merkle": "./dest/merkle/index.js" + "./merkle": "./dest/merkle/index.js", + "./simulation": "./dest/simulator/index.js" }, "typedocOptions": { "entryPoints": [ diff --git a/yarn-project/circuits.js/src/structs/proof.ts b/yarn-project/circuits.js/src/structs/proof.ts index c2a16b9616b..ff339c9345f 100644 --- a/yarn-project/circuits.js/src/structs/proof.ts +++ b/yarn-project/circuits.js/src/structs/proof.ts @@ -1,5 +1,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +const EMPTY_PROOF_SIZE = 42; + /** * The Proof class is a wrapper around the circuits proof. * Underlying it is a buffer of proof data in a form a barretenberg prover understands. @@ -47,5 +49,5 @@ export class Proof { * @returns The empty "proof". */ export function makeEmptyProof() { - return new Proof(Buffer.alloc(0)); + return new Proof(Buffer.alloc(EMPTY_PROOF_SIZE, 0)); } diff --git a/yarn-project/end-to-end/package.json b/yarn-project/end-to-end/package.json index a5aedd32dcd..f61000a26d3 100644 --- a/yarn-project/end-to-end/package.json +++ b/yarn-project/end-to-end/package.json @@ -32,8 +32,10 @@ "@aztec/noir-contracts.js": "workspace:^", "@aztec/p2p": "workspace:^", "@aztec/protocol-contracts": "workspace:^", + "@aztec/prover-client": "workspace:^", "@aztec/pxe": "workspace:^", "@aztec/sequencer-client": "workspace:^", + "@aztec/simulator": "workspace:^", "@aztec/types": "workspace:^", "@aztec/world-state": "workspace:^", "@jest/globals": "^29.5.0", @@ -50,6 +52,7 @@ "crypto-browserify": "^3.12.0", "glob": "^10.3.10", "jest": "^29.5.0", + "jest-mock-extended": "^3.0.5", "koa": "^2.14.2", "koa-static": "^5.0.0", "levelup": "^5.1.1", 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 415d3aca702..d6a568def0b 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 @@ -1,5 +1,13 @@ +import { ArchiveSource } from '@aztec/archiver'; import { getConfigEnvVars } from '@aztec/aztec-node'; import { AztecAddress, Body, Fr, GlobalVariables, L2Actor, L2Block, createDebugLogger, mockTx } from '@aztec/aztec.js'; +// eslint-disable-next-line no-restricted-imports +import { + ProcessedTx, + ProvingSuccess, + makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricalTreeRoots, + makeProcessedTx, +} from '@aztec/circuit-types'; import { EthAddress, Header, @@ -20,21 +28,14 @@ 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'; -import { - EmptyRollupProver, - L1Publisher, - RealRollupCircuitSimulator, - SoloBlockBuilder, - WASMSimulator, - getL1Publisher, - getVerificationKeys, - makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricalTreeRoots, - makeProcessedTx, -} from '@aztec/sequencer-client'; -import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; +import { TxProver } from '@aztec/prover-client'; +import { L1Publisher, getL1Publisher } from '@aztec/sequencer-client'; +import { WASMSimulator } from '@aztec/simulator'; +import { MerkleTrees, ServerWorldStateSynchronizer, WorldStateConfig } from '@aztec/world-state'; import { beforeEach, describe, expect, it } from '@jest/globals'; import * as fs from 'fs'; +import { MockProxy, mock } from 'jest-mock-extended'; import { Account, Address, @@ -80,12 +81,14 @@ describe('L1Publisher integration', () => { let publisher: L1Publisher; let l2Proof: Buffer; - let builder: SoloBlockBuilder; - let builderDb: MerkleTreeOperations; + let builder: TxProver; + let builderDb: MerkleTrees; // The header of the last block let prevHeader: Header; + let blockSource: MockProxy; + const chainId = createEthereumChain(config.rpcUrl, config.apiKey).chainInfo.id; let coinbase: EthAddress; @@ -123,12 +126,16 @@ describe('L1Publisher integration', () => { client: publicClient, }); - builderDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); - const vks = getVerificationKeys(); - const simulator = new RealRollupCircuitSimulator(new WASMSimulator()); - const prover = new EmptyRollupProver(); - builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); - + const tmpStore = openTmpStore(); + builderDb = await MerkleTrees.new(tmpStore); + blockSource = mock(); + blockSource.getBlocks.mockResolvedValue([]); + const worldStateConfig: WorldStateConfig = { + worldStateBlockCheckIntervalMS: 10000, + l2QueueSize: 10, + }; + const worldStateSynchronizer = new ServerWorldStateSynchronizer(tmpStore, builderDb, blockSource, worldStateConfig); + builder = await TxProver.new({}, worldStateSynchronizer, new WASMSimulator()); l2Proof = Buffer.alloc(0); publisher = getL1Publisher({ @@ -143,7 +150,7 @@ describe('L1Publisher integration', () => { coinbase = config.coinbase || EthAddress.random(); feeRecipient = config.feeRecipient || AztecAddress.random(); - prevHeader = await builderDb.buildInitialHeader(); + prevHeader = await builderDb.buildInitialHeader(false); }, 100_000); const makeEmptyProcessedTx = () => { @@ -297,6 +304,19 @@ describe('L1Publisher integration', () => { fs.writeFileSync(path, output, 'utf8'); }; + const buildBlock = async ( + globalVariables: GlobalVariables, + txs: ProcessedTx[], + l1ToL2Messages: Fr[], + emptyTx: ProcessedTx, + ) => { + const blockTicket = await builder.startNewBlock(txs.length, globalVariables, l1ToL2Messages, emptyTx); + for (const tx of txs) { + await builder.addNewTx(tx); + } + return blockTicket; + }; + it('Block body is correctly published to AvailabilityOracle', async () => { const body = Body.random(); // `sendPublishTx` function is private so I am hacking around TS here. I think it's ok for test purposes. @@ -360,7 +380,9 @@ describe('L1Publisher integration', () => { coinbase, feeRecipient, ); - const [block] = await builder.buildL2Block(globalVariables, txs, currentL1ToL2Messages); + const ticket = await buildBlock(globalVariables, txs, currentL1ToL2Messages, makeEmptyProcessedTx()); + const result = await ticket.provingPromise; + const block = (result as ProvingSuccess).block; prevHeader = block.header; const newL2ToL1MsgsArray = block.body.txEffects.flatMap(txEffect => txEffect.l2ToL1Msgs); @@ -441,7 +463,9 @@ describe('L1Publisher integration', () => { coinbase, feeRecipient, ); - const [block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); + const blockTicket = await buildBlock(globalVariables, txs, l1ToL2Messages, makeEmptyProcessedTx()); + const result = await blockTicket.provingPromise; + const block = (result as ProvingSuccess).block; prevHeader = block.header; writeJson(`empty_block_${i}`, block, [], AztecAddress.ZERO, deployerAccount.address); diff --git a/yarn-project/end-to-end/tsconfig.json b/yarn-project/end-to-end/tsconfig.json index 1b1651c944b..159d8f7cea1 100644 --- a/yarn-project/end-to-end/tsconfig.json +++ b/yarn-project/end-to-end/tsconfig.json @@ -54,12 +54,18 @@ { "path": "../protocol-contracts" }, + { + "path": "../prover-client" + }, { "path": "../pxe" }, { "path": "../sequencer-client" }, + { + "path": "../simulator" + }, { "path": "../types" }, diff --git a/yarn-project/prover-client/package.json b/yarn-project/prover-client/package.json index 49b0dba2623..a1b03a69775 100644 --- a/yarn-project/prover-client/package.json +++ b/yarn-project/prover-client/package.json @@ -30,14 +30,23 @@ "rootDir": "./src" }, "dependencies": { + "@aztec/circuit-types": "workspace:^", + "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/kv-store": "workspace:^", + "@aztec/noir-protocol-circuits-types": "workspace:^", + "@aztec/simulator": "workspace:^", + "@aztec/world-state": "workspace:^", + "lodash.chunk": "^4.2.0", "tslib": "^2.4.0" }, "devDependencies": { "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", + "@types/memdown": "^3.0.0", "@types/node": "^18.7.23", "jest": "^29.5.0", + "jest-mock-extended": "^3.0.3", "ts-jest": "^29.1.0", "ts-node": "^10.9.1", "typescript": "^5.0.4" diff --git a/yarn-project/prover-client/src/config.ts b/yarn-project/prover-client/src/config.ts new file mode 100644 index 00000000000..a6d2cefb83c --- /dev/null +++ b/yarn-project/prover-client/src/config.ts @@ -0,0 +1,22 @@ +/** + * The prover configuration. + */ +export interface ProverConfig { + /** The working directory to use for simulation/proving */ + acvmWorkingDirectory?: string; + /** The path to the ACVM binary */ + acvmBinaryPath?: string; +} + +/** + * Returns the prover configuration from the environment variables. + * Note: If an environment variable is not set, the default value is used. + * @returns The prover configuration. + */ +export function getConfigEnvVars(): ProverConfig { + const { ACVM_WORKING_DIRECTORY, ACVM_BINARY_PATH } = process.env; + return { + acvmWorkingDirectory: ACVM_WORKING_DIRECTORY ? ACVM_WORKING_DIRECTORY : undefined, + acvmBinaryPath: ACVM_BINARY_PATH ? ACVM_BINARY_PATH : undefined, + }; +} diff --git a/yarn-project/prover-client/src/dummy-prover.ts b/yarn-project/prover-client/src/dummy-prover.ts new file mode 100644 index 00000000000..d2c1f4842e4 --- /dev/null +++ b/yarn-project/prover-client/src/dummy-prover.ts @@ -0,0 +1,45 @@ +import { + L2Block, + PROVING_STATUS, + ProcessedTx, + ProverClient, + ProvingSuccess, + ProvingTicket, +} from '@aztec/circuit-types'; +import { GlobalVariables, makeEmptyProof } from '@aztec/circuits.js'; +import { Fr } from '@aztec/foundation/fields'; + +export class DummyProver implements ProverClient { + public start(): Promise { + return Promise.resolve(); + } + + public stop(): Promise { + return Promise.resolve(); + } + + public static new(): Promise { + return Promise.resolve(new DummyProver()); + } + + startNewBlock( + _numTxs: number, + _globalVariables: GlobalVariables, + _newL1ToL2Messages: Fr[], + _emptyTx: ProcessedTx, + ): Promise { + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + proof: makeEmptyProof(), + block: L2Block.empty(), + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; + return Promise.resolve(ticket); + } + + addNewTx(_tx: ProcessedTx): Promise { + return Promise.resolve(); + } +} diff --git a/yarn-project/prover-client/src/index.ts b/yarn-project/prover-client/src/index.ts index 90fe8eacdf0..46368c53575 100644 --- a/yarn-project/prover-client/src/index.ts +++ b/yarn-project/prover-client/src/index.ts @@ -1,4 +1,8 @@ -/** - * A placeholder for the Prover Client. - */ -export class ProverClient {} +export * from './tx-prover/tx-prover.js'; +export * from './config.js'; +export * from './dummy-prover.js'; + +// Exported for integration_l1_publisher.test.ts +export { getVerificationKeys } from './mocks/verification_keys.js'; +export { EmptyRollupProver } from './prover/empty.js'; +export { RealRollupCircuitSimulator } from './simulator/rollup.js'; diff --git a/yarn-project/sequencer-client/src/mocks/verification_keys.ts b/yarn-project/prover-client/src/mocks/verification_keys.ts similarity index 100% rename from yarn-project/sequencer-client/src/mocks/verification_keys.ts rename to yarn-project/prover-client/src/mocks/verification_keys.ts diff --git a/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts new file mode 100644 index 00000000000..07ed89f7a6c --- /dev/null +++ b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts @@ -0,0 +1,595 @@ +import { MerkleTreeId, ProcessedTx } from '@aztec/circuit-types'; +import { + ARCHIVE_HEIGHT, + AppendOnlyTreeSnapshot, + BaseOrMergeRollupPublicInputs, + BaseParityInputs, + BaseRollupInputs, + ConstantRollupData, + Fr, + GlobalVariables, + L1_TO_L2_MSG_SUBTREE_HEIGHT, + L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, + MAX_NEW_NULLIFIERS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MembershipWitness, + MergeRollupInputs, + NOTE_HASH_SUBTREE_HEIGHT, + NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, + NULLIFIER_SUBTREE_HEIGHT, + NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, + NULLIFIER_TREE_HEIGHT, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, + NullifierLeafPreimage, + PUBLIC_DATA_SUBTREE_HEIGHT, + PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, + PUBLIC_DATA_TREE_HEIGHT, + PartialStateReference, + PreviousRollupData, + Proof, + PublicDataTreeLeaf, + PublicDataTreeLeafPreimage, + ROLLUP_VK_TREE_HEIGHT, + RollupKernelCircuitPublicInputs, + RollupKernelData, + RollupTypes, + RootParityInput, + RootParityInputs, + RootRollupInputs, + RootRollupPublicInputs, + StateDiffHints, + StateReference, + VK_TREE_HEIGHT, + VerificationKey, +} from '@aztec/circuits.js'; +import { assertPermutation, makeTuple } from '@aztec/foundation/array'; +import { DebugLogger } from '@aztec/foundation/log'; +import { Tuple, assertLength, toFriendlyJSON } from '@aztec/foundation/serialize'; +import { MerkleTreeOperations } from '@aztec/world-state'; + +import { VerificationKeys, getVerificationKeys } from '../mocks/verification_keys.js'; +import { RollupProver } from '../prover/index.js'; +import { RollupSimulator } from '../simulator/rollup.js'; + +// Denotes fields that are not used now, but will be in the future +const FUTURE_FR = new Fr(0n); +const FUTURE_NUM = 0; + +// Denotes fields that should be deleted +const DELETE_FR = new Fr(0n); + +/** + * Type representing the names of the trees for the base rollup. + */ +type BaseTreeNames = 'NoteHashTree' | 'ContractTree' | 'NullifierTree' | 'PublicDataTree'; +/** + * Type representing the names of the trees. + */ +export type TreeNames = BaseTreeNames | 'L1ToL2MessageTree' | 'Archive'; + +// Builds the base rollup inputs, updating the contract, nullifier, and data trees in the process +export async function buildBaseRollupInput( + tx: ProcessedTx, + globalVariables: GlobalVariables, + db: MerkleTreeOperations, +) { + // Get trees info before any changes hit + const constants = await getConstantRollupData(globalVariables, db); + const start = new PartialStateReference( + await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, db), + await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, db), + await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, db), + ); + // Get the subtree sibling paths for the circuit + const noteHashSubtreeSiblingPathArray = await getSubtreeSiblingPath( + MerkleTreeId.NOTE_HASH_TREE, + NOTE_HASH_SUBTREE_HEIGHT, + db, + ); + + const noteHashSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, i => + i < noteHashSubtreeSiblingPathArray.length ? noteHashSubtreeSiblingPathArray[i] : Fr.ZERO, + ); + + // Update the note hash trees with the new items being inserted to get the new roots + // that will be used by the next iteration of the base rollup circuit, skipping the empty ones + const newNoteHashes = tx.data.combinedData.newNoteHashes.map(x => x.value.toBuffer()); + await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, newNoteHashes); + + // The read witnesses for a given TX should be generated before the writes of the same TX are applied. + // All reads that refer to writes in the same tx are transient and can be simplified out. + const txPublicDataReadsInfo = await getPublicDataReadsInfo(tx, db); + const txPublicDataUpdateRequestInfo = await processPublicDataUpdateRequests(tx, db); + + // Update the nullifier tree, capturing the low nullifier info for each individual operation + const { + lowLeavesWitnessData: nullifierWitnessLeaves, + newSubtreeSiblingPath: newNullifiersSubtreeSiblingPath, + sortedNewLeaves: sortedNewNullifiers, + sortedNewLeavesIndexes, + } = await db.batchInsert( + MerkleTreeId.NULLIFIER_TREE, + tx.data.combinedData.newNullifiers.map(sideEffectLinkedToNoteHash => sideEffectLinkedToNoteHash.value.toBuffer()), + NULLIFIER_SUBTREE_HEIGHT, + ); + if (nullifierWitnessLeaves === undefined) { + throw new Error(`Could not craft nullifier batch insertion proofs`); + } + + // Extract witness objects from returned data + const nullifierPredecessorMembershipWitnessesWithoutPadding: MembershipWitness[] = + nullifierWitnessLeaves.map(l => + MembershipWitness.fromBufferArray(l.index, assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT)), + ); + + const nullifierSubtreeSiblingPathArray = newNullifiersSubtreeSiblingPath.toFields(); + + const nullifierSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, i => + i < nullifierSubtreeSiblingPathArray.length ? nullifierSubtreeSiblingPathArray[i] : Fr.ZERO, + ); + + const publicDataSiblingPath = txPublicDataUpdateRequestInfo.newPublicDataSubtreeSiblingPath; + + const stateDiffHints = StateDiffHints.from({ + nullifierPredecessorPreimages: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => + i < nullifierWitnessLeaves.length + ? (nullifierWitnessLeaves[i].leafPreimage as NullifierLeafPreimage) + : NullifierLeafPreimage.empty(), + ), + nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => + i < nullifierPredecessorMembershipWitnessesWithoutPadding.length + ? nullifierPredecessorMembershipWitnessesWithoutPadding[i] + : makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), + ), + sortedNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortedNewNullifiers[i])), + sortedNullifierIndexes: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), + noteHashSubtreeSiblingPath, + nullifierSubtreeSiblingPath, + publicDataSiblingPath, + }); + + const blockHash = tx.data.constants.historicalHeader.hash(); + const archiveRootMembershipWitness = await getMembershipWitnessFor( + blockHash, + MerkleTreeId.ARCHIVE, + ARCHIVE_HEIGHT, + db, + ); + + return BaseRollupInputs.from({ + kernelData: getKernelDataFor(tx, getVerificationKeys()), + start, + stateDiffHints, + + sortedPublicDataWrites: txPublicDataUpdateRequestInfo.sortedPublicDataWrites, + sortedPublicDataWritesIndexes: txPublicDataUpdateRequestInfo.sortedPublicDataWritesIndexes, + lowPublicDataWritesPreimages: txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages, + lowPublicDataWritesMembershipWitnesses: txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses, + publicDataReadsPreimages: txPublicDataReadsInfo.newPublicDataReadsPreimages, + publicDataReadsMembershipWitnesses: txPublicDataReadsInfo.newPublicDataReadsWitnesses, + + archiveRootMembershipWitness, + + constants, + }); +} + +export function createMergeRollupInputs( + left: [BaseOrMergeRollupPublicInputs, Proof], + right: [BaseOrMergeRollupPublicInputs, Proof], +) { + const vks = getVerificationKeys(); + const vk = left[0].rollupType === RollupTypes.Base ? vks.baseRollupCircuit : vks.mergeRollupCircuit; + const mergeInputs = new MergeRollupInputs([ + getPreviousRollupDataFromPublicInputs(left[0], left[1], vk), + getPreviousRollupDataFromPublicInputs(right[0], right[1], vk), + ]); + return mergeInputs; +} + +export async function executeMergeRollupCircuit( + mergeInputs: MergeRollupInputs, + simulator: RollupSimulator, + prover: RollupProver, + logger?: DebugLogger, +): Promise<[BaseOrMergeRollupPublicInputs, Proof]> { + logger?.debug(`Running merge rollup circuit`); + const output = await simulator.mergeRollupCircuit(mergeInputs); + const proof = await prover.getMergeRollupProof(mergeInputs, output); + return [output, proof]; +} + +export async function executeRootRollupCircuit( + left: [BaseOrMergeRollupPublicInputs, Proof], + right: [BaseOrMergeRollupPublicInputs, Proof], + l1ToL2Roots: RootParityInput, + newL1ToL2Messages: Tuple, + simulator: RollupSimulator, + prover: RollupProver, + db: MerkleTreeOperations, + logger?: DebugLogger, +): Promise<[RootRollupPublicInputs, Proof]> { + logger?.debug(`Running root rollup circuit`); + const rootInput = await getRootRollupInput(...left, ...right, l1ToL2Roots, newL1ToL2Messages, db); + + // Update the local trees to include the new l1 to l2 messages + await db.appendLeaves( + MerkleTreeId.L1_TO_L2_MESSAGE_TREE, + newL1ToL2Messages.map(m => m.toBuffer()), + ); + + // Simulate and get proof for the root circuit + const rootOutput = await simulator.rootRollupCircuit(rootInput); + + const rootProof = await prover.getRootRollupProof(rootInput, rootOutput); + + //TODO(@PhilWindle) Move this to orchestrator to ensure that we are still on the same block + // Update the archive with the latest block header + logger?.debug(`Updating and validating root trees`); + await db.updateArchive(rootOutput.header); + + await validateRootOutput(rootOutput, db); + + return [rootOutput, rootProof]; +} + +// Validate that the roots of all local trees match the output of the root circuit simulation +export async function validateRootOutput(rootOutput: RootRollupPublicInputs, db: MerkleTreeOperations) { + await Promise.all([ + validateState(rootOutput.header.state, db), + validateSimulatedTree(await getTreeSnapshot(MerkleTreeId.ARCHIVE, db), rootOutput.archive, 'Archive'), + ]); +} + +export async function validateState(state: StateReference, db: MerkleTreeOperations) { + const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map( + async (id: MerkleTreeId) => { + return { key: id, value: await getTreeSnapshot(id, db) }; + }, + ); + const snapshots: Map = new Map( + (await Promise.all(promises)).map(obj => [obj.key, obj.value]), + ); + validatePartialState(state.partial, snapshots); + validateSimulatedTree( + await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db), + state.l1ToL2MessageTree, + 'L1ToL2MessageTree', + ); +} + +// Builds the inputs for the root rollup circuit, without making any changes to trees +export async function getRootRollupInput( + rollupOutputLeft: BaseOrMergeRollupPublicInputs, + rollupProofLeft: Proof, + rollupOutputRight: BaseOrMergeRollupPublicInputs, + rollupProofRight: Proof, + l1ToL2Roots: RootParityInput, + newL1ToL2Messages: Tuple, + db: MerkleTreeOperations, +) { + const vks = getVerificationKeys(); + const vk = rollupOutputLeft.rollupType === RollupTypes.Base ? vks.baseRollupCircuit : vks.mergeRollupCircuit; + const previousRollupData: RootRollupInputs['previousRollupData'] = [ + getPreviousRollupDataFromPublicInputs(rollupOutputLeft, rollupProofLeft, vk), + getPreviousRollupDataFromPublicInputs(rollupOutputRight, rollupProofRight, vk), + ]; + + const getRootTreeSiblingPath = async (treeId: MerkleTreeId) => { + const { size } = await db.getTreeInfo(treeId); + const path = await db.getSiblingPath(treeId, size); + return path.toFields(); + }; + + const newL1ToL2MessageTreeRootSiblingPathArray = await getSubtreeSiblingPath( + MerkleTreeId.L1_TO_L2_MESSAGE_TREE, + L1_TO_L2_MSG_SUBTREE_HEIGHT, + db, + ); + + const newL1ToL2MessageTreeRootSiblingPath = makeTuple( + L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, + i => (i < newL1ToL2MessageTreeRootSiblingPathArray.length ? newL1ToL2MessageTreeRootSiblingPathArray[i] : Fr.ZERO), + 0, + ); + + // Get tree snapshots + const startL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db); + + // Get blocks tree + const startArchiveSnapshot = await getTreeSnapshot(MerkleTreeId.ARCHIVE, db); + const newArchiveSiblingPathArray = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE); + + const newArchiveSiblingPath = makeTuple( + ARCHIVE_HEIGHT, + i => (i < newArchiveSiblingPathArray.length ? newArchiveSiblingPathArray[i] : Fr.ZERO), + 0, + ); + + return RootRollupInputs.from({ + previousRollupData, + l1ToL2Roots, + newL1ToL2Messages, + newL1ToL2MessageTreeRootSiblingPath, + startL1ToL2MessageTreeSnapshot, + startArchiveSnapshot, + newArchiveSiblingPath, + }); +} + +export function getPreviousRollupDataFromPublicInputs( + rollupOutput: BaseOrMergeRollupPublicInputs, + rollupProof: Proof, + vk: VerificationKey, +) { + return new PreviousRollupData( + rollupOutput, + rollupProof, + vk, + + // MembershipWitness for a VK tree to be implemented in the future + FUTURE_NUM, + new MembershipWitness( + ROLLUP_VK_TREE_HEIGHT, + BigInt(FUTURE_NUM), + makeTuple(ROLLUP_VK_TREE_HEIGHT, () => FUTURE_FR), + ), + ); +} + +export async function getConstantRollupData( + globalVariables: GlobalVariables, + db: MerkleTreeOperations, +): Promise { + return ConstantRollupData.from({ + baseRollupVkHash: DELETE_FR, + mergeRollupVkHash: DELETE_FR, + privateKernelVkTreeRoot: FUTURE_FR, + publicKernelVkTreeRoot: FUTURE_FR, + lastArchive: await getTreeSnapshot(MerkleTreeId.ARCHIVE, db), + globalVariables, + }); +} + +export async function getTreeSnapshot(id: MerkleTreeId, db: MerkleTreeOperations): Promise { + const treeInfo = await db.getTreeInfo(id); + return new AppendOnlyTreeSnapshot(Fr.fromBuffer(treeInfo.root), Number(treeInfo.size)); +} + +export function getKernelDataFor(tx: ProcessedTx, vks: VerificationKeys): RollupKernelData { + const inputs = new RollupKernelCircuitPublicInputs( + tx.data.aggregationObject, + tx.data.combinedData, + tx.data.constants, + ); + return new RollupKernelData( + inputs, + tx.proof, + + // VK for the kernel circuit + vks.privateKernelCircuit, + + // MembershipWitness for a VK tree to be implemented in the future + FUTURE_NUM, + assertLength(Array(VK_TREE_HEIGHT).fill(FUTURE_FR), VK_TREE_HEIGHT), + ); +} + +export function makeEmptyMembershipWitness(height: N) { + return new MembershipWitness( + height, + 0n, + makeTuple(height, () => Fr.ZERO), + ); +} + +export async function getPublicDataReadsInfo(tx: ProcessedTx, db: MerkleTreeOperations) { + const newPublicDataReadsWitnesses: Tuple< + MembershipWitness, + typeof MAX_PUBLIC_DATA_READS_PER_TX + > = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT, 0n)); + + const newPublicDataReadsPreimages: Tuple = makeTuple( + MAX_PUBLIC_DATA_READS_PER_TX, + () => PublicDataTreeLeafPreimage.empty(), + ); + + for (const i in tx.data.validationRequests.publicDataReads) { + const leafSlot = tx.data.validationRequests.publicDataReads[i].leafSlot.value; + const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot); + if (!lowLeafResult) { + throw new Error(`Public data tree should have one initial leaf`); + } + const preimage = await db.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index); + const path = await db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index); + newPublicDataReadsWitnesses[i] = new MembershipWitness( + PUBLIC_DATA_TREE_HEIGHT, + BigInt(lowLeafResult.index), + path.toTuple(), + ); + newPublicDataReadsPreimages[i] = preimage! as PublicDataTreeLeafPreimage; + } + return { + newPublicDataReadsWitnesses, + newPublicDataReadsPreimages, + }; +} + +export async function processPublicDataUpdateRequests(tx: ProcessedTx, db: MerkleTreeOperations) { + const combinedPublicDataUpdateRequests = tx.data.combinedData.publicDataUpdateRequests.map(updateRequest => { + return new PublicDataTreeLeaf(updateRequest.leafSlot, updateRequest.newValue); + }); + const { lowLeavesWitnessData, newSubtreeSiblingPath, sortedNewLeaves, sortedNewLeavesIndexes } = await db.batchInsert( + MerkleTreeId.PUBLIC_DATA_TREE, + combinedPublicDataUpdateRequests.map(x => x.toBuffer()), + // TODO(#3675) remove oldValue from update requests + PUBLIC_DATA_SUBTREE_HEIGHT, + ); + + if (lowLeavesWitnessData === undefined) { + throw new Error(`Could not craft public data batch insertion proofs`); + } + + const sortedPublicDataWrites = makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { + return PublicDataTreeLeaf.fromBuffer(sortedNewLeaves[i]); + }); + + const sortedPublicDataWritesIndexes = makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { + return sortedNewLeavesIndexes[i]; + }); + + const subtreeSiblingPathAsFields = newSubtreeSiblingPath.toFields(); + const newPublicDataSubtreeSiblingPath = makeTuple(PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, i => { + return subtreeSiblingPathAsFields[i]; + }); + + const lowPublicDataWritesMembershipWitnesses: Tuple< + MembershipWitness, + typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + > = makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { + const witness = lowLeavesWitnessData[i]; + return MembershipWitness.fromBufferArray( + witness.index, + assertLength(witness.siblingPath.toBufferArray(), PUBLIC_DATA_TREE_HEIGHT), + ); + }); + + const lowPublicDataWritesPreimages: Tuple = + makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { + return lowLeavesWitnessData[i].leafPreimage as PublicDataTreeLeafPreimage; + }); + + // validate that the sortedPublicDataWrites and sortedPublicDataWritesIndexes are in the correct order + // otherwise it will just fail in the circuit + assertPermutation(combinedPublicDataUpdateRequests, sortedPublicDataWrites, sortedPublicDataWritesIndexes, (a, b) => + a.equals(b), + ); + + return { + lowPublicDataWritesPreimages, + lowPublicDataWritesMembershipWitnesses, + newPublicDataSubtreeSiblingPath, + sortedPublicDataWrites, + sortedPublicDataWritesIndexes, + }; +} + +export async function getSubtreeSiblingPath( + treeId: MerkleTreeId, + subtreeHeight: number, + db: MerkleTreeOperations, +): Promise { + const nextAvailableLeafIndex = await db.getTreeInfo(treeId).then(t => t.size); + const fullSiblingPath = await db.getSiblingPath(treeId, nextAvailableLeafIndex); + + // Drop the first subtreeHeight items since we only care about the path to the subtree root + return fullSiblingPath.getSubtreeSiblingPath(subtreeHeight).toFields(); +} + +// Scan a tree searching for a specific value and return a membership witness proof for it +export async function getMembershipWitnessFor( + value: Fr, + treeId: MerkleTreeId, + height: N, + db: MerkleTreeOperations, +): Promise> { + // If this is an empty tx, then just return zeroes + if (value.isZero()) { + return makeEmptyMembershipWitness(height); + } + + const index = await db.findLeafIndex(treeId, value.toBuffer()); + if (index === undefined) { + throw new Error(`Leaf with value ${value} not found in tree ${MerkleTreeId[treeId]}`); + } + const path = await db.getSiblingPath(treeId, index); + return new MembershipWitness(height, index, assertLength(path.toFields(), height)); +} + +export async function executeBaseRollupCircuit( + tx: ProcessedTx, + inputs: BaseRollupInputs, + treeSnapshots: Map, + simulator: RollupSimulator, + prover: RollupProver, + logger?: DebugLogger, +): Promise<[BaseOrMergeRollupPublicInputs, Proof]> { + logger?.(`Running base rollup for ${tx.hash}`); + const rollupOutput = await simulator.baseRollupCircuit(inputs); + validatePartialState(rollupOutput.end, treeSnapshots); + const proof = await prover.getBaseRollupProof(inputs, rollupOutput); + return [rollupOutput, proof]; +} + +export function validatePartialState( + partialState: PartialStateReference, + treeSnapshots: Map, +) { + validateSimulatedTree(treeSnapshots.get(MerkleTreeId.NOTE_HASH_TREE)!, partialState.noteHashTree, 'NoteHashTree'); + validateSimulatedTree(treeSnapshots.get(MerkleTreeId.NULLIFIER_TREE)!, partialState.nullifierTree, 'NullifierTree'); + validateSimulatedTree( + treeSnapshots.get(MerkleTreeId.PUBLIC_DATA_TREE)!, + partialState.publicDataTree, + 'PublicDataTree', + ); +} + +// Helper for comparing two trees snapshots +export function validateSimulatedTree( + localTree: AppendOnlyTreeSnapshot, + simulatedTree: AppendOnlyTreeSnapshot, + name: TreeNames, + label?: string, +) { + if (!simulatedTree.root.toBuffer().equals(localTree.root.toBuffer())) { + throw new Error(`${label ?? name} tree root mismatch (local ${localTree.root}, simulated ${simulatedTree.root})`); + } + if (simulatedTree.nextAvailableLeafIndex !== localTree.nextAvailableLeafIndex) { + throw new Error( + `${label ?? name} tree next available leaf index mismatch (local ${localTree.nextAvailableLeafIndex}, simulated ${ + simulatedTree.nextAvailableLeafIndex + })`, + ); + } +} + +export async function executeBaseParityCircuit( + inputs: BaseParityInputs, + simulator: RollupSimulator, + prover: RollupProver, + logger?: DebugLogger, +): Promise { + logger?.debug(`Running base parity circuit`); + const parityPublicInputs = await simulator.baseParityCircuit(inputs); + const proof = await prover.getBaseParityProof(inputs, parityPublicInputs); + return new RootParityInput(proof, parityPublicInputs); +} + +export async function executeRootParityCircuit( + inputs: RootParityInputs, + simulator: RollupSimulator, + prover: RollupProver, + logger?: DebugLogger, +): Promise { + logger?.debug(`Running root parity circuit`); + const parityPublicInputs = await simulator.rootParityCircuit(inputs); + const proof = await prover.getRootParityProof(inputs, parityPublicInputs); + return new RootParityInput(proof, parityPublicInputs); +} + +export function validateTx(tx: ProcessedTx) { + const txHeader = tx.data.constants.historicalHeader; + if (txHeader.state.l1ToL2MessageTree.isZero()) { + throw new Error(`Empty L1 to L2 messages tree in tx: ${toFriendlyJSON(tx)}`); + } + if (txHeader.state.partial.noteHashTree.isZero()) { + throw new Error(`Empty note hash tree in tx: ${toFriendlyJSON(tx)}`); + } + if (txHeader.state.partial.nullifierTree.isZero()) { + throw new Error(`Empty nullifier tree in tx: ${toFriendlyJSON(tx)}`); + } + if (txHeader.state.partial.publicDataTree.isZero()) { + throw new Error(`Empty public data tree in tx: ${toFriendlyJSON(tx)}`); + } +} diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts new file mode 100644 index 00000000000..73a2bd9fe2d --- /dev/null +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts @@ -0,0 +1,596 @@ +import { + MerkleTreeId, + PROVING_STATUS, + ProcessedTx, + ProvingSuccess, + makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricalTreeRoots, + makeProcessedTx, + mockTx, +} from '@aztec/circuit-types'; +import { + AztecAddress, + BaseOrMergeRollupPublicInputs, + EthAddress, + Fr, + GlobalVariables, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, + MAX_NEW_NOTE_HASHES_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX, + MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, + MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_REVERTIBLE_NOTE_HASHES_PER_TX, + MAX_REVERTIBLE_NULLIFIERS_PER_TX, + MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + NULLIFIER_SUBTREE_HEIGHT, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, + PUBLIC_DATA_SUBTREE_HEIGHT, + Proof, + PublicDataTreeLeaf, + PublicDataUpdateRequest, + PublicKernelCircuitPublicInputs, + RootRollupPublicInputs, + SideEffect, + SideEffectLinkedToNoteHash, + sideEffectCmp, +} from '@aztec/circuits.js'; +import { + fr, + makeBaseOrMergeRollupPublicInputs, + makeNewSideEffect, + makeNewSideEffectLinkedToNoteHash, + makeParityPublicInputs, + makeProof, + makeRootRollupPublicInputs, +} 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'; +import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; + +import { MockProxy, mock } from 'jest-mock-extended'; +import { type MemDown, default as memdown } from 'memdown'; + +import { getVerificationKeys } from '../mocks/verification_keys.js'; +import { RollupProver } from '../prover/index.js'; +import { RollupSimulator } from '../simulator/rollup.js'; +import { ProvingOrchestrator } from './orchestrator.js'; + +export const createMemDown = () => (memdown as any)() as MemDown; + +describe('prover/tx-prover', () => { + let builder: ProvingOrchestrator; + let builderDb: MerkleTreeOperations; + let expectsDb: MerkleTreeOperations; + + let simulator: MockProxy; + let prover: MockProxy; + + let blockNumber: number; + let baseRollupOutputLeft: BaseOrMergeRollupPublicInputs; + let baseRollupOutputRight: BaseOrMergeRollupPublicInputs; + let rootRollupOutput: RootRollupPublicInputs; + let mockL1ToL2Messages: Fr[]; + + let globalVariables: GlobalVariables; + + const emptyProof = new Proof(Buffer.alloc(32, 0)); + + const chainId = Fr.ZERO; + const version = Fr.ZERO; + const coinbase = EthAddress.ZERO; + const feeRecipient = AztecAddress.ZERO; + + beforeEach(async () => { + blockNumber = 3; + globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO, coinbase, feeRecipient); + + builderDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); + expectsDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); + simulator = mock(); + prover = mock(); + builder = new ProvingOrchestrator(builderDb, new WASMSimulator(), getVerificationKeys(), prover); + + // Create mock l1 to L2 messages + mockL1ToL2Messages = new Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)); + + // Create mock outputs for simulator + baseRollupOutputLeft = makeBaseOrMergeRollupPublicInputs(0, globalVariables); + baseRollupOutputRight = makeBaseOrMergeRollupPublicInputs(0, globalVariables); + rootRollupOutput = makeRootRollupPublicInputs(0); + rootRollupOutput.header.globalVariables = globalVariables; + + // Set up mocks + prover.getBaseParityProof.mockResolvedValue(emptyProof); + prover.getRootParityProof.mockResolvedValue(emptyProof); + prover.getBaseRollupProof.mockResolvedValue(emptyProof); + prover.getMergeRollupProof.mockResolvedValue(emptyProof); + prover.getRootRollupProof.mockResolvedValue(emptyProof); + simulator.baseParityCircuit + .mockResolvedValueOnce(makeParityPublicInputs(1)) + .mockResolvedValue(makeParityPublicInputs(2)) + .mockResolvedValue(makeParityPublicInputs(3)) + .mockResolvedValueOnce(makeParityPublicInputs(4)); + simulator.rootParityCircuit.mockResolvedValueOnce(makeParityPublicInputs(5)); + simulator.baseRollupCircuit + .mockResolvedValueOnce(baseRollupOutputLeft) + .mockResolvedValueOnce(baseRollupOutputRight); + simulator.rootRollupCircuit.mockResolvedValue(rootRollupOutput); + }, 20_000); + + const makeEmptyProcessedTx = async () => { + const header = await builderDb.buildInitialHeader(); + return makeEmptyProcessedTxFromHistoricalTreeRoots(header, chainId, version); + }; + + // Updates the expectedDb trees based on the new note hashes, contracts, and nullifiers from these txs + const updateExpectedTreesFromTxs = async (txs: ProcessedTx[]) => { + await expectsDb.appendLeaves( + MerkleTreeId.NOTE_HASH_TREE, + txs.flatMap(tx => + padArrayEnd( + [...tx.data.endNonRevertibleData.newNoteHashes, ...tx.data.end.newNoteHashes] + .filter(x => !x.isEmpty()) + .sort(sideEffectCmp), + SideEffect.empty(), + MAX_NEW_NOTE_HASHES_PER_TX, + ).map(l => l.value.toBuffer()), + ), + ); + await expectsDb.batchInsert( + MerkleTreeId.NULLIFIER_TREE, + txs.flatMap(tx => + padArrayEnd( + [...tx.data.endNonRevertibleData.newNullifiers, ...tx.data.end.newNullifiers] + .filter(x => !x.isEmpty()) + .sort(sideEffectCmp), + SideEffectLinkedToNoteHash.empty(), + MAX_NEW_NULLIFIERS_PER_TX, + ).map(x => x.value.toBuffer()), + ), + NULLIFIER_SUBTREE_HEIGHT, + ); + for (const tx of txs) { + await expectsDb.batchInsert( + MerkleTreeId.PUBLIC_DATA_TREE, + [...tx.data.endNonRevertibleData.publicDataUpdateRequests, ...tx.data.end.publicDataUpdateRequests].map( + write => { + return new PublicDataTreeLeaf(write.leafSlot, write.newValue).toBuffer(); + }, + ), + PUBLIC_DATA_SUBTREE_HEIGHT, + ); + } + }; + + // const updateL1ToL2MessageTree = async (l1ToL2Messages: Fr[]) => { + // const asBuffer = l1ToL2Messages.map(m => m.toBuffer()); + // await expectsDb.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, asBuffer); + // }; + + // const updateArchive = async () => { + // const blockHash = rootRollupOutput.header.hash(); + // await expectsDb.appendLeaves(MerkleTreeId.ARCHIVE, [blockHash.toBuffer()]); + // }; + + // const getTreeSnapshot = async (tree: MerkleTreeId) => { + // const treeInfo = await expectsDb.getTreeInfo(tree); + // return new AppendOnlyTreeSnapshot(Fr.fromBuffer(treeInfo.root), Number(treeInfo.size)); + // }; + + // const getPartialStateReference = async () => { + // return new PartialStateReference( + // await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE), + // await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE), + // await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE), + // ); + // }; + + // const getStateReference = async () => { + // return new StateReference( + // await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE), + // await getPartialStateReference(), + // ); + // }; + + // const buildMockSimulatorInputs = async () => { + // const kernelOutput = makePrivateKernelTailCircuitPublicInputs(); + // kernelOutput.constants.historicalHeader = await expectsDb.buildInitialHeader(); + // kernelOutput.needsAppLogic = false; + // kernelOutput.needsSetup = false; + // kernelOutput.needsTeardown = false; + + // const tx = makeProcessedTx( + // new Tx( + // kernelOutput, + // emptyProof, + // makeEmptyLogs(), + // makeEmptyLogs(), + // times(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makePublicCallRequest), + // ), + // ); + + // const txs = [tx, await makeEmptyProcessedTx()]; + + // // Calculate what would be the tree roots after the first tx and update mock circuit output + // await updateExpectedTreesFromTxs([txs[0]]); + // baseRollupOutputLeft.end = await getPartialStateReference(); + // baseRollupOutputLeft.txsEffectsHash = to2Fields(toTxEffect(tx).hash()); + + // // Same for the tx on the right + // await updateExpectedTreesFromTxs([txs[1]]); + // baseRollupOutputRight.end = await getPartialStateReference(); + // baseRollupOutputRight.txsEffectsHash = to2Fields(toTxEffect(tx).hash()); + + // // Update l1 to l2 message tree + // await updateL1ToL2MessageTree(mockL1ToL2Messages); + + // // Collect all new nullifiers, commitments, and contracts from all txs in this block + // const txEffects: TxEffect[] = txs.map(tx => toTxEffect(tx)); + + // const body = new Body(padArrayEnd(mockL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), txEffects); + // // We are constructing the block here just to get body hash/calldata hash so we can pass in an empty archive and header + // const l2Block = L2Block.fromFields({ + // archive: AppendOnlyTreeSnapshot.zero(), + // header: Header.empty(), + // // Only the values below go to body hash/calldata hash + // body, + // }); + + // // Now we update can make the final header, compute the block hash and update archive + // rootRollupOutput.header.globalVariables = globalVariables; + // rootRollupOutput.header.contentCommitment.txsEffectsHash = l2Block.body.getTxsEffectsHash(); + // rootRollupOutput.header.state = await getStateReference(); + + // await updateArchive(); + // rootRollupOutput.archive = await getTreeSnapshot(MerkleTreeId.ARCHIVE); + + // return txs; + // }; + + describe('error handling', () => { + beforeEach(async () => { + builder = await ProvingOrchestrator.new(builderDb, new WASMSimulator(), prover); + }); + + it.each([ + [ + 'Base Rollup Failed', + () => { + prover.getBaseRollupProof.mockRejectedValue('Base Rollup Failed'); + }, + ], + [ + 'Merge Rollup Failed', + () => { + prover.getMergeRollupProof.mockRejectedValue('Merge Rollup Failed'); + }, + ], + [ + 'Root Rollup Failed', + () => { + prover.getRootRollupProof.mockRejectedValue('Root Rollup Failed'); + }, + ], + [ + 'Base Parity Failed', + () => { + prover.getBaseParityProof.mockRejectedValue('Base Parity Failed'); + }, + ], + [ + 'Root Parity Failed', + () => { + prover.getRootParityProof.mockRejectedValue('Root Parity Failed'); + }, + ], + ] as const)( + 'handles a %s error', + async (message: string, fn: () => void) => { + fn(); + const txs = await Promise.all([ + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + ]); + + const blockTicket = await builder.startNewBlock(txs.length, globalVariables, [], await makeEmptyProcessedTx()); + + for (const tx of txs) { + await builder.addNewTx(tx); + } + await expect(blockTicket.provingPromise).resolves.toEqual({ status: PROVING_STATUS.FAILURE, reason: message }); + }, + 60000, + ); + + afterEach(async () => { + await builder.stop(); + }); + }); + + describe('circuits simulator', () => { + beforeEach(async () => { + builder = await ProvingOrchestrator.new(builderDb, new WASMSimulator(), prover); + }); + + afterEach(async () => { + await builder.stop(); + }); + + const makeBloatedProcessedTx = async (seed = 0x1) => { + seed *= MAX_NEW_NULLIFIERS_PER_TX; // Ensure no clashing given incremental seeds + const tx = mockTx(seed); + const kernelOutput = PublicKernelCircuitPublicInputs.empty(); + kernelOutput.constants.historicalHeader = await builderDb.buildInitialHeader(); + kernelOutput.end.publicDataUpdateRequests = makeTuple( + MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + i => new PublicDataUpdateRequest(fr(i), fr(i + 10)), + seed + 0x500, + ); + kernelOutput.endNonRevertibleData.publicDataUpdateRequests = makeTuple( + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + i => new PublicDataUpdateRequest(fr(i), fr(i + 10)), + seed + 0x600, + ); + + const processedTx = makeProcessedTx(tx, kernelOutput, makeProof()); + + processedTx.data.end.newNoteHashes = makeTuple( + MAX_REVERTIBLE_NOTE_HASHES_PER_TX, + makeNewSideEffect, + seed + 0x100, + ); + processedTx.data.endNonRevertibleData.newNoteHashes = makeTuple( + MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, + makeNewSideEffect, + seed + 0x100, + ); + processedTx.data.end.newNullifiers = makeTuple( + MAX_REVERTIBLE_NULLIFIERS_PER_TX, + makeNewSideEffectLinkedToNoteHash, + seed + 0x100000, + ); + + processedTx.data.endNonRevertibleData.newNullifiers = makeTuple( + MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, + makeNewSideEffectLinkedToNoteHash, + seed + 0x100000 + MAX_REVERTIBLE_NULLIFIERS_PER_TX, + ); + + 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()); + + return processedTx; + }; + + it.each([ + [0, 4], + [1, 4], + [4, 4], + [0, 16], + [4, 16], + ] as const)( + 'builds an L2 block with %i bloated txs and %i txs total', + async (bloatedCount: number, totalCount: number) => { + const noteHashTreeBefore = await builderDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE); + const txs = [ + ...(await Promise.all(times(bloatedCount, makeBloatedProcessedTx))), + ...(await Promise.all(times(totalCount - bloatedCount, makeEmptyProcessedTx))), + ]; + + const blockTicket = await builder.startNewBlock( + txs.length, + globalVariables, + mockL1ToL2Messages, + await makeEmptyProcessedTx(), + ); + + for (const tx of txs) { + await builder.addNewTx(tx); + } + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + + expect((result as ProvingSuccess).block.number).toEqual(blockNumber); + + await updateExpectedTreesFromTxs(txs); + const noteHashTreeAfter = await builderDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE); + + if (bloatedCount > 0) { + expect(noteHashTreeAfter.root).not.toEqual(noteHashTreeBefore.root); + } + + const expectedNoteHashTreeAfter = await expectsDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE).then(t => t.root); + expect(noteHashTreeAfter.root).toEqual(expectedNoteHashTreeAfter); + }, + 60000, + ); + + it('builds an empty L2 block', async () => { + const txs = await Promise.all([ + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + ]); + + const blockTicket = await builder.startNewBlock(txs.length, globalVariables, [], await makeEmptyProcessedTx()); + + for (const tx of txs) { + await builder.addNewTx(tx); + } + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + expect((result as ProvingSuccess).block.number).toEqual(blockNumber); + }, 30_000); + + it('builds a block with 1 transaction', async () => { + const txs = await Promise.all([makeEmptyProcessedTx()]); + + const blockTicket = await builder.startNewBlock(txs.length, globalVariables, [], await makeEmptyProcessedTx()); + + for (const tx of txs) { + await builder.addNewTx(tx); + } + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + expect((result as ProvingSuccess).block.number).toEqual(blockNumber); + }, 30_000); + + it('builds a mixed L2 block', async () => { + const txs = await Promise.all([ + makeBloatedProcessedTx(1), + makeBloatedProcessedTx(2), + makeBloatedProcessedTx(3), + makeBloatedProcessedTx(4), + ]); + + const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); + + const blockTicket = await builder.startNewBlock( + txs.length, + globalVariables, + l1ToL2Messages, + await makeEmptyProcessedTx(), + ); + + for (const tx of txs) { + await builder.addNewTx(tx); + } + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + expect((result as ProvingSuccess).block.number).toEqual(blockNumber); + }, 200_000); + + it('builds a block concurrently with transactions', async () => { + const txs = await Promise.all([ + makeBloatedProcessedTx(1), + makeBloatedProcessedTx(2), + makeBloatedProcessedTx(3), + makeBloatedProcessedTx(4), + ]); + + const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); + + const blockTicket = await builder.startNewBlock( + txs.length, + globalVariables, + l1ToL2Messages, + await makeEmptyProcessedTx(), + ); + + for (const tx of txs) { + await builder.addNewTx(tx); + await sleep(1000); + } + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + expect((result as ProvingSuccess).block.number).toEqual(blockNumber); + }, 200_000); + + // it('cancels current blocks and switches to new ones', async () => { + // const txs = await Promise.all([ + // makeBloatedProcessedTx(1), + // makeBloatedProcessedTx(2), + // makeBloatedProcessedTx(3), + // makeBloatedProcessedTx(4), + // ]); + + // const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); + + // const blockPromise1 = await builder.startNewBlock( + // txs.length, + // globalVariables, + // l1ToL2Messages, + // await makeEmptyProcessedTx(), + // ); + + // builder.addNewTx(txs[0]); + + // const blockPromise2 = await builder.startNewBlock( + // txs.length, + // globalVariables, + // l1ToL2Messages, + // await makeEmptyProcessedTx(), + // ); + + // builder.addNewTx(txs[0]); + + // await expect(blockPromise1).rejects.toEqual('Block cancelled'); + + // const result = await blockPromise2; + // expect(result.block.number).toEqual(blockNumber); + // }, 200_000); + + it('builds an unbalanced L2 block', async () => { + const txs = await Promise.all([makeEmptyProcessedTx(), makeEmptyProcessedTx(), makeEmptyProcessedTx()]); + + const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); + + const blockTicket = await builder.startNewBlock( + txs.length, + globalVariables, + l1ToL2Messages, + await makeEmptyProcessedTx(), + ); + + for (const tx of txs) { + await builder.addNewTx(tx); + } + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + expect((result as ProvingSuccess).block.number).toEqual(blockNumber); + }, 200_000); + + it('throws if adding too many transactions', async () => { + const txs = await Promise.all([ + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + makeEmptyProcessedTx(), + ]); + + const blockTicket = await builder.startNewBlock(txs.length, globalVariables, [], await makeEmptyProcessedTx()); + + for (const tx of txs) { + await builder.addNewTx(tx); + } + + await expect(async () => await builder.addNewTx(await makeEmptyProcessedTx())).rejects.toThrow( + `Rollup already contains 4 transactions`, + ); + + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); + expect((result as ProvingSuccess).block.number).toEqual(blockNumber); + }, 30_000); + + it('throws if adding a transaction before start', async () => { + await expect(async () => await builder.addNewTx(await makeEmptyProcessedTx())).rejects.toThrow( + `Invalid proving state, call startNewBlock before adding transactions`, + ); + }, 30_000); + + it('rejects if too many l1 to l2 messages are provided', async () => { + // Assemble a fake transaction + const l1ToL2Messages = new Array(100).fill(new Fr(0n)); + await expect( + async () => await builder.startNewBlock(1, globalVariables, l1ToL2Messages, await makeEmptyProcessedTx()), + ).rejects.toThrow('Too many L1 to L2 messages'); + }); + }); +}); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts new file mode 100644 index 00000000000..d813a9dc0d1 --- /dev/null +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -0,0 +1,522 @@ +import { Body, L2Block, MerkleTreeId, ProcessedTx, TxEffect, toTxEffect } from '@aztec/circuit-types'; +import { PROVING_STATUS, ProvingResult, ProvingTicket } from '@aztec/circuit-types/interfaces'; +import { CircuitSimulationStats } from '@aztec/circuit-types/stats'; +import { + AppendOnlyTreeSnapshot, + BaseOrMergeRollupPublicInputs, + BaseParityInputs, + BaseRollupInputs, + Fr, + GlobalVariables, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, + NUM_BASE_PARITY_PER_ROOT_PARITY, + Proof, + RootParityInput, + RootParityInputs, +} from '@aztec/circuits.js'; +import { padArrayEnd } from '@aztec/foundation/collection'; +import { MemoryFifo } from '@aztec/foundation/fifo'; +import { createDebugLogger } from '@aztec/foundation/log'; +import { Tuple } from '@aztec/foundation/serialize'; +import { sleep } from '@aztec/foundation/sleep'; +import { elapsed } from '@aztec/foundation/timer'; +import { SimulationProvider } from '@aztec/simulator'; +import { MerkleTreeOperations } from '@aztec/world-state'; + +import { inspect } from 'util'; + +import { VerificationKeys, getVerificationKeys } from '../mocks/verification_keys.js'; +import { RollupProver } from '../prover/index.js'; +import { RealRollupCircuitSimulator, RollupSimulator } from '../simulator/rollup.js'; +import { + buildBaseRollupInput, + createMergeRollupInputs, + executeBaseParityCircuit, + executeBaseRollupCircuit, + executeMergeRollupCircuit, + executeRootParityCircuit, + executeRootRollupCircuit, + getTreeSnapshot, + validateTx, +} from './block-building-helpers.js'; +import { MergeRollupInputData, PROVING_JOB_TYPE, ProvingJob, ProvingState } from './proving-state.js'; + +const logger = createDebugLogger('aztec:prover:proving-orchestrator'); + +/** + * Implements an event driven proving scheduler to build the recursive proof tree. The idea being: + * 1. Transactions are provided to the scheduler post simulation. + * 2. Tree insertions are performed as required to generate transaction specific proofs + * 3. Those transaction specific proofs are generated in the necessary order accounting for dependencies + * 4. Once a transaction is proven, it will be incorporated into a merge proof + * 5. Merge proofs are produced at each level of the tree until the root proof is produced + * + * The proving implementation is determined by the provided prover implementation. This could be for example a local prover or a remote prover pool. + */ + +const SLEEP_TIME = 50; +const MAX_CONCURRENT_JOBS = 64; + +enum PROMISE_RESULT { + SLEEP, + OPERATIONS, +} + +/** + * The orchestrator, managing the flow of recursive proving operations required to build the rollup proof tree. + */ +export class ProvingOrchestrator { + private provingState: ProvingState | undefined = undefined; + private jobQueue: MemoryFifo = new MemoryFifo(); + private simulator: RollupSimulator; + private jobProcessPromise?: Promise; + private stopped = false; + constructor( + private db: MerkleTreeOperations, + simulationProvider: SimulationProvider, + protected vks: VerificationKeys, + private prover: RollupProver, + private maxConcurrentJobs = MAX_CONCURRENT_JOBS, + ) { + this.simulator = new RealRollupCircuitSimulator(simulationProvider); + } + + public static new(db: MerkleTreeOperations, simulationProvider: SimulationProvider, prover: RollupProver) { + const orchestrator = new ProvingOrchestrator(db, simulationProvider, getVerificationKeys(), prover); + orchestrator.start(); + return Promise.resolve(orchestrator); + } + + public start() { + this.jobProcessPromise = this.processJobQueue(); + } + + public async stop() { + this.stopped = true; + this.jobQueue.cancel(); + await this.jobProcessPromise; + } + + /** + * Starts off a new block + * @param numTxs - The number of real transactions in the block + * @param globalVariables - The global variables for the block + * @param l1ToL2Messages - The l1 to l2 messages for the block + * @param emptyTx - The instance of an empty transaction to be used to pad this block + * @returns A proving ticket, containing a promise notifying of proving completion + */ + public async startNewBlock( + numTxs: number, + globalVariables: GlobalVariables, + l1ToL2Messages: Fr[], + emptyTx: ProcessedTx, + ): Promise { + if (this.provingState && !this.provingState.isFinished()) { + throw new Error("Can't start a new block until the previous block is finished"); + } + logger.info(`Starting new block with ${numTxs} transactions`); + // we start the block by enqueueing all of the base parity circuits + let baseParityInputs: BaseParityInputs[] = []; + let l1ToL2MessagesPadded: Tuple; + try { + l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); + } catch (err) { + throw new Error('Too many L1 to L2 messages'); + } + baseParityInputs = Array.from({ length: NUM_BASE_PARITY_PER_ROOT_PARITY }, (_, i) => + BaseParityInputs.fromSlice(l1ToL2MessagesPadded, i), + ); + + //TODO:(@PhilWindle) Temporary until we figure out when to perform L1 to L2 insertions to make state consistency easier. + await Promise.resolve(); + + const promise = new Promise((resolve, reject) => { + this.provingState = new ProvingState( + numTxs, + resolve, + reject, + globalVariables, + l1ToL2MessagesPadded, + baseParityInputs.length, + emptyTx, + ); + }).catch((reason: string) => ({ status: PROVING_STATUS.FAILURE, reason } as const)); + + for (let i = 0; i < baseParityInputs.length; i++) { + this.enqueueJob(this.provingState!.Id, PROVING_JOB_TYPE.BASE_PARITY, () => + this.runBaseParityCircuit(baseParityInputs[i], i, this.provingState!.Id), + ); + } + + const ticket: ProvingTicket = { + provingPromise: promise, + }; + return ticket; + } + + /** + * The interface to add a simulated transaction to the scheduler + * @param tx - The transaction to be proven + */ + public async addNewTx(tx: ProcessedTx): Promise { + if (!this.provingState) { + throw new Error(`Invalid proving state, call startNewBlock before adding transactions`); + } + + if (this.provingState.numTxs === this.provingState.transactionsReceived) { + throw new Error(`Rollup already contains ${this.provingState.transactionsReceived} transactions`); + } + + validateTx(tx); + + logger.info(`Received transaction :${tx.hash}`); + + // We start the transaction by enqueueing the state updates + + const txIndex = this.provingState!.addNewTx(tx); + // we start this transaction off by performing it's tree insertions and + await this.prepareBaseRollupInputs(BigInt(txIndex), tx, this.provingState!.globalVariables, this.provingState!.Id); + + if (this.provingState.transactionsReceived === this.provingState.numTxs) { + // we need to pad the rollup with empty transactions + const numPaddingTxs = this.provingState.numPaddingTxs; + for (let i = 0; i < numPaddingTxs; i++) { + const paddingTxIndex = this.provingState.addNewTx(this.provingState.emptyTx); + await this.prepareBaseRollupInputs( + BigInt(paddingTxIndex), + this.provingState!.emptyTx, + this.provingState!.globalVariables, + this.provingState!.Id, + ); + } + } + } + + /** + * Enqueue a job to be scheduled + * @param stateIdentifier - For state Id verification + * @param jobType - The type of job to be queued + * @param job - The actual job, returns a promise notifying of the job's completion + */ + private enqueueJob(stateIdentifier: string, jobType: PROVING_JOB_TYPE, job: () => Promise) { + if (!this.provingState!.verifyState(stateIdentifier)) { + logger(`Discarding job for state ID: ${stateIdentifier}`); + return; + } + // We use a 'safeJob'. We don't want promise rejections in the proving pool, we want to capture the error here + // and reject the proving job whilst keeping the event loop free of rejections + const safeJob = async () => { + try { + await job(); + } catch (err) { + logger.error(`Error thrown when proving job type ${PROVING_JOB_TYPE[jobType]}: ${err}`); + this.provingState!.reject(`${err}`, stateIdentifier); + } + }; + const provingJob: ProvingJob = { + type: jobType, + operation: safeJob, + }; + this.jobQueue.put(provingJob); + } + + // Updates the merkle trees for a transaction. The first enqueued job for a transaction + private async prepareBaseRollupInputs( + index: bigint, + tx: ProcessedTx, + globalVariables: GlobalVariables, + stateIdentifier: string, + ) { + const inputs = await buildBaseRollupInput(tx, globalVariables, this.db); + const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map( + async (id: MerkleTreeId) => { + return { key: id, value: await getTreeSnapshot(id, this.db) }; + }, + ); + const treeSnapshots: Map = new Map( + (await Promise.all(promises)).map(obj => [obj.key, obj.value]), + ); + + if (!this.provingState?.verifyState(stateIdentifier)) { + logger(`Discarding job for state ID: ${stateIdentifier}`); + return; + } + + this.enqueueJob(stateIdentifier, PROVING_JOB_TYPE.BASE_ROLLUP, () => + this.runBaseRollup(index, tx, inputs, treeSnapshots, stateIdentifier), + ); + } + + // Stores the intermediate inputs prepared for a merge proof + private storeMergeInputs( + currentLevel: bigint, + currentIndex: bigint, + mergeInputs: [BaseOrMergeRollupPublicInputs, Proof], + ) { + const mergeLevel = currentLevel - 1n; + const indexWithinMergeLevel = currentIndex >> 1n; + const mergeIndex = 2n ** mergeLevel - 1n + indexWithinMergeLevel; + const subscript = Number(mergeIndex); + const indexWithinMerge = Number(currentIndex & 1n); + const ready = this.provingState!.storeMergeInputs(mergeInputs, indexWithinMerge, subscript); + return { ready, indexWithinMergeLevel, mergeLevel, mergeInputData: this.provingState!.getMergeInputs(subscript) }; + } + + // Executes the base rollup circuit and stored the output as intermediate state for the parent merge/root circuit + // Executes the next level of merge if all inputs are available + private async runBaseRollup( + index: bigint, + tx: ProcessedTx, + inputs: BaseRollupInputs, + treeSnapshots: Map, + stateIdentifier: string, + ) { + const [duration, baseRollupOutputs] = await elapsed(() => + executeBaseRollupCircuit(tx, inputs, treeSnapshots, this.simulator, this.prover, logger), + ); + logger.debug(`Simulated base rollup circuit`, { + eventName: 'circuit-simulation', + circuitName: 'base-rollup', + duration, + inputSize: inputs.toBuffer().length, + outputSize: baseRollupOutputs[0].toBuffer().length, + } satisfies CircuitSimulationStats); + if (!this.provingState?.verifyState(stateIdentifier)) { + logger(`Discarding job for state ID: ${stateIdentifier}`); + return; + } + const currentLevel = this.provingState!.numMergeLevels + 1n; + logger.info(`Completed base rollup at index ${index}, current level ${currentLevel}`); + this.storeAndExecuteNextMergeLevel(currentLevel, index, baseRollupOutputs, stateIdentifier); + } + + // Executes the merge rollup circuit and stored the output as intermediate state for the parent merge/root circuit + // Executes the next level of merge if all inputs are available + private async runMergeRollup( + level: bigint, + index: bigint, + mergeInputData: MergeRollupInputData, + stateIdentifier: string, + ) { + const circuitInputs = createMergeRollupInputs( + [mergeInputData.inputs[0]!, mergeInputData.proofs[0]!], + [mergeInputData.inputs[1]!, mergeInputData.proofs[1]!], + ); + const [duration, circuitOutputs] = await elapsed(() => + executeMergeRollupCircuit(circuitInputs, this.simulator, this.prover, logger), + ); + logger.debug(`Simulated merge rollup circuit`, { + eventName: 'circuit-simulation', + circuitName: 'merge-rollup', + duration, + inputSize: circuitInputs.toBuffer().length, + outputSize: circuitOutputs[0].toBuffer().length, + } satisfies CircuitSimulationStats); + if (!this.provingState?.verifyState(stateIdentifier)) { + logger(`Discarding job for state ID: ${stateIdentifier}`); + return; + } + logger.info(`Completed merge rollup at level ${level}, index ${index}`); + this.storeAndExecuteNextMergeLevel(level, index, circuitOutputs, stateIdentifier); + } + + // Executes the root rollup circuit + private async runRootRollup( + mergeInputData: MergeRollupInputData, + rootParityInput: RootParityInput, + stateIdentifier: string, + ) { + const [circuitsOutput, proof] = await executeRootRollupCircuit( + [mergeInputData.inputs[0]!, mergeInputData.proofs[0]!], + [mergeInputData.inputs[1]!, mergeInputData.proofs[1]!], + rootParityInput, + this.provingState!.newL1ToL2Messages, + this.simulator, + this.prover, + this.db, + logger, + ); + logger.info(`Completed root rollup`); + // Collect all new nullifiers, commitments, and contracts from all txs in this block + const txEffects: TxEffect[] = this.provingState!.allTxs.map(tx => toTxEffect(tx)); + + const blockBody = new Body(txEffects); + + const l2Block = L2Block.fromFields({ + archive: circuitsOutput.archive, + header: circuitsOutput.header, + body: blockBody, + }); + + if (!l2Block.body.getTxsEffectsHash().equals(circuitsOutput.header.contentCommitment.txsEffectsHash)) { + logger(inspect(blockBody)); + throw new Error( + `Txs effects hash mismatch, ${l2Block.body + .getTxsEffectsHash() + .toString('hex')} == ${circuitsOutput.header.contentCommitment.txsEffectsHash.toString('hex')} `, + ); + } + + const provingResult: ProvingResult = { + status: PROVING_STATUS.SUCCESS, + block: l2Block, + proof, + }; + logger.info(`Successfully proven block ${l2Block.number}!`); + this.provingState!.resolve(provingResult, stateIdentifier); + } + + // Executes the base parity circuit and stores the intermediate state for the root parity circuit + // Enqueues the root parity circuit if all inputs are available + private async runBaseParityCircuit(inputs: BaseParityInputs, index: number, stateIdentifier: string) { + const [duration, circuitOutputs] = await elapsed(() => + executeBaseParityCircuit(inputs, this.simulator, this.prover, logger), + ); + logger.debug(`Simulated base parity circuit`, { + eventName: 'circuit-simulation', + circuitName: 'base-parity', + duration, + inputSize: inputs.toBuffer().length, + outputSize: circuitOutputs.toBuffer().length, + } satisfies CircuitSimulationStats); + if (!this.provingState?.verifyState(stateIdentifier)) { + logger(`Discarding job for state ID: ${stateIdentifier}`); + return; + } + this.provingState!.setRootParityInputs(circuitOutputs, index); + + if (!this.provingState!.areRootParityInputsReady()) { + // not ready to run the root parity circuit yet + return; + } + const rootParityInputs = new RootParityInputs( + this.provingState!.rootParityInput as Tuple, + ); + this.enqueueJob(stateIdentifier, PROVING_JOB_TYPE.ROOT_PARITY, () => + this.runRootParityCircuit(rootParityInputs, stateIdentifier), + ); + } + + // Runs the root parity circuit ans stored the outputs + // Enqueues the root rollup proof if all inputs are available + private async runRootParityCircuit(inputs: RootParityInputs, stateIdentifier: string) { + const [duration, circuitOutputs] = await elapsed(() => + executeRootParityCircuit(inputs, this.simulator, this.prover, logger), + ); + logger.debug(`Simulated root parity circuit`, { + eventName: 'circuit-simulation', + circuitName: 'root-parity', + duration, + inputSize: inputs.toBuffer().length, + outputSize: circuitOutputs.toBuffer().length, + } satisfies CircuitSimulationStats); + if (!this.provingState?.verifyState(stateIdentifier)) { + logger(`Discarding job for state ID: ${stateIdentifier}`); + return; + } + this.provingState!.finalRootParityInput = circuitOutputs; + this.checkAndExecuteRootRollup(stateIdentifier); + } + + private checkAndExecuteRootRollup(stateIdentifier: string) { + if (!this.provingState!.isReadyForRootRollup()) { + logger('Not ready for root'); + return; + } + this.enqueueJob(stateIdentifier, PROVING_JOB_TYPE.ROOT_ROLLUP, () => + this.runRootRollup( + this.provingState!.getMergeInputs(0)!, + this.provingState!.finalRootParityInput!, + stateIdentifier, + ), + ); + } + + private storeAndExecuteNextMergeLevel( + currentLevel: bigint, + currentIndex: bigint, + mergeInputData: [BaseOrMergeRollupPublicInputs, Proof], + stateIdentifier: string, + ) { + const result = this.storeMergeInputs(currentLevel, currentIndex, mergeInputData); + + // Are we ready to execute the next circuit? + if (!result.ready) { + return; + } + + if (result.mergeLevel === 0n) { + this.checkAndExecuteRootRollup(stateIdentifier); + } else { + // onto the next merge level + this.enqueueJob(stateIdentifier, PROVING_JOB_TYPE.MERGE_ROLLUP, () => + this.runMergeRollup(result.mergeLevel, result.indexWithinMergeLevel, result.mergeInputData, stateIdentifier), + ); + } + } + + /** + * Process the job queue + * Works by managing an input queue of proof requests and an active pool of proving 'jobs' + */ + private async processJobQueue() { + // Used for determining the current state of a proving job + const promiseState = (p: Promise) => { + const t = {}; + return Promise.race([p, t]).then( + v => (v === t ? 'pending' : 'fulfilled'), + () => 'rejected', + ); + }; + + // Just a short break between managing the sets of requests and active jobs + const createSleepPromise = () => + sleep(SLEEP_TIME).then(_ => { + return PROMISE_RESULT.SLEEP; + }); + + let sleepPromise = createSleepPromise(); + let promises: Promise[] = []; + while (!this.stopped) { + // first look for more work + if (this.jobQueue.length() && promises.length < this.maxConcurrentJobs) { + // more work could be available + const job = await this.jobQueue.get(); + if (job !== null) { + // a proving job, add it to the pool of outstanding jobs + promises.push(job.operation()); + } + // continue adding more work + continue; + } + + // no more work to add, here we wait for any outstanding jobs to finish and/or sleep a little + try { + const ops = Promise.race(promises).then(_ => { + return PROMISE_RESULT.OPERATIONS; + }); + const result = await Promise.race([sleepPromise, ops]); + if (result === PROMISE_RESULT.SLEEP) { + // this is the sleep promise + // we simply setup the promise again and go round the loop checking for more work + sleepPromise = createSleepPromise(); + continue; + } + } catch (err) { + // We shouldn't get here as all jobs should be wrapped in a 'safeJob' meaning they don't fail! + logger.error(`Unexpected error in proving orchestrator ${err}`); + } + + // one or more of the jobs completed, remove them + const pendingPromises = []; + for (const jobPromise of promises) { + const state = await promiseState(jobPromise); + if (state === 'pending') { + pendingPromises.push(jobPromise); + } + } + // eslint-disable-next-line @typescript-eslint/no-floating-promises + promises = pendingPromises; + } + } +} diff --git a/yarn-project/prover-client/src/orchestrator/proving-state.ts b/yarn-project/prover-client/src/orchestrator/proving-state.ts new file mode 100644 index 00000000000..232f7ad40e5 --- /dev/null +++ b/yarn-project/prover-client/src/orchestrator/proving-state.ts @@ -0,0 +1,182 @@ +import { ProcessedTx, ProvingResult } from '@aztec/circuit-types'; +import { + BaseOrMergeRollupPublicInputs, + Fr, + GlobalVariables, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, + Proof, + RootParityInput, +} from '@aztec/circuits.js'; +import { randomBytes } from '@aztec/foundation/crypto'; +import { Tuple } from '@aztec/foundation/serialize'; + +/** + * Enums and structs to communicate the type of work required in each request. + */ +export enum PROVING_JOB_TYPE { + STATE_UPDATE, + BASE_ROLLUP, + MERGE_ROLLUP, + ROOT_ROLLUP, + BASE_PARITY, + ROOT_PARITY, +} + +export type ProvingJob = { + type: PROVING_JOB_TYPE; + operation: () => Promise; +}; + +export type MergeRollupInputData = { + inputs: [BaseOrMergeRollupPublicInputs | undefined, BaseOrMergeRollupPublicInputs | undefined]; + proofs: [Proof | undefined, Proof | undefined]; +}; + +/** + * The current state of the proving schedule. Contains the raw inputs (txs) and intermediate state to generate every constituent proof in the tree. + * Carries an identifier so we can identify if the proving state is discarded and a new one started. + * Captures resolve and reject callbacks to provide a promise base interface to the consumer of our proving. + */ +export class ProvingState { + private stateIdentifier: string; + private mergeRollupInputs: MergeRollupInputData[] = []; + private rootParityInputs: Array = []; + private finalRootParityInputs: RootParityInput | undefined; + private finished = false; + private txs: ProcessedTx[] = []; + constructor( + public readonly numTxs: number, + private completionCallback: (result: ProvingResult) => void, + private rejectionCallback: (reason: string) => void, + public readonly globalVariables: GlobalVariables, + public readonly newL1ToL2Messages: Tuple, + numRootParityInputs: number, + public readonly emptyTx: ProcessedTx, + ) { + this.stateIdentifier = randomBytes(32).toString('hex'); + this.rootParityInputs = Array.from({ length: numRootParityInputs }).map(_ => undefined); + } + + public get baseMergeLevel() { + return BigInt(Math.ceil(Math.log2(this.totalNumTxs)) - 1); + } + + public get numMergeLevels() { + return this.baseMergeLevel; + } + + public get Id() { + return this.stateIdentifier; + } + + public get numPaddingTxs() { + return this.totalNumTxs - this.numTxs; + } + + public get totalNumTxs() { + const realTxs = Math.max(2, this.numTxs); + const pow2Txs = Math.ceil(Math.log2(realTxs)); + return 2 ** pow2Txs; + } + + public addNewTx(tx: ProcessedTx) { + this.txs.push(tx); + return this.txs.length - 1; + } + + public get transactionsReceived() { + return this.txs.length; + } + + public get finalRootParityInput() { + return this.finalRootParityInputs; + } + + public set finalRootParityInput(input: RootParityInput | undefined) { + this.finalRootParityInputs = input; + } + + public get rootParityInput() { + return this.rootParityInputs; + } + + public verifyState(stateId: string) { + return stateId === this.stateIdentifier && !this.finished; + } + + public get allTxs() { + return this.txs; + } + + public storeMergeInputs( + mergeInputs: [BaseOrMergeRollupPublicInputs, Proof], + indexWithinMerge: number, + indexOfMerge: number, + ) { + if (!this.mergeRollupInputs[indexOfMerge]) { + const mergeInputData: MergeRollupInputData = { + inputs: [undefined, undefined], + proofs: [undefined, undefined], + }; + mergeInputData.inputs[indexWithinMerge] = mergeInputs[0]; + mergeInputData.proofs[indexWithinMerge] = mergeInputs[1]; + this.mergeRollupInputs[indexOfMerge] = mergeInputData; + return false; + } + const mergeInputData = this.mergeRollupInputs[indexOfMerge]; + mergeInputData.inputs[indexWithinMerge] = mergeInputs[0]; + mergeInputData.proofs[indexWithinMerge] = mergeInputs[1]; + return true; + } + + public getMergeInputs(indexOfMerge: number) { + return this.mergeRollupInputs[indexOfMerge]; + } + + public isReadyForRootRollup() { + if (this.mergeRollupInputs[0] === undefined) { + return false; + } + if (this.mergeRollupInputs[0].inputs.findIndex(p => !p) !== -1) { + return false; + } + if (this.finalRootParityInput === undefined) { + return false; + } + return true; + } + + public setRootParityInputs(inputs: RootParityInput, index: number) { + this.rootParityInputs[index] = inputs; + } + + public areRootParityInputsReady() { + return this.rootParityInputs.findIndex(p => !p) === -1; + } + + public reject(reason: string, stateIdentifier: string) { + if (!this.verifyState(stateIdentifier)) { + return; + } + if (this.finished) { + return; + } + this.finished = true; + this.rejectionCallback(reason); + } + + public resolve(result: ProvingResult, stateIdentifier: string) { + if (!this.verifyState(stateIdentifier)) { + return; + } + if (this.finished) { + return; + } + this.finished = true; + this.completionCallback(result); + } + + public isFinished() { + return this.finished; + } +} diff --git a/yarn-project/sequencer-client/src/prover/empty.ts b/yarn-project/prover-client/src/prover/empty.ts similarity index 100% rename from yarn-project/sequencer-client/src/prover/empty.ts rename to yarn-project/prover-client/src/prover/empty.ts diff --git a/yarn-project/sequencer-client/src/prover/index.ts b/yarn-project/prover-client/src/prover/index.ts similarity index 100% rename from yarn-project/sequencer-client/src/prover/index.ts rename to yarn-project/prover-client/src/prover/index.ts diff --git a/yarn-project/sequencer-client/src/simulator/rollup.ts b/yarn-project/prover-client/src/simulator/rollup.ts similarity index 75% rename from yarn-project/sequencer-client/src/simulator/rollup.ts rename to yarn-project/prover-client/src/simulator/rollup.ts index e87f6e38816..5101c07b2d9 100644 --- a/yarn-project/sequencer-client/src/simulator/rollup.ts +++ b/yarn-project/prover-client/src/simulator/rollup.ts @@ -28,9 +28,43 @@ import { convertRootRollupInputsToWitnessMap, convertRootRollupOutputsFromWitnessMap, } from '@aztec/noir-protocol-circuits-types'; +import { SimulationProvider, WASMSimulator } from '@aztec/simulator'; -import { RollupSimulator, WASMSimulator } from './index.js'; -import { SimulationProvider } from './simulation_provider.js'; +/** + * Circuit simulator for the rollup circuits. + */ +export interface RollupSimulator { + /** + * Simulates the base parity circuit from its inputs. + * @param inputs - Inputs to the circuit. + * @returns The public inputs of the parity circuit. + */ + baseParityCircuit(inputs: BaseParityInputs): Promise; + /** + * Simulates the root parity circuit from its inputs. + * @param inputs - Inputs to the circuit. + * @returns The public inputs of the parity circuit. + */ + rootParityCircuit(inputs: RootParityInputs): Promise; + /** + * Simulates the base rollup circuit from its inputs. + * @param input - Inputs to the circuit. + * @returns The public inputs as outputs of the simulation. + */ + baseRollupCircuit(input: BaseRollupInputs): Promise; + /** + * Simulates the merge rollup circuit from its inputs. + * @param input - Inputs to the circuit. + * @returns The public inputs as outputs of the simulation. + */ + mergeRollupCircuit(input: MergeRollupInputs): Promise; + /** + * Simulates the root rollup circuit from its inputs. + * @param input - Inputs to the circuit. + * @returns The public inputs as outputs of the simulation. + */ + rootRollupCircuit(input: RootRollupInputs): Promise; +} /** * Implements the rollup circuit simulator. @@ -121,7 +155,6 @@ export class RealRollupCircuitSimulator implements RollupSimulator { inputSize: input.toBuffer().length, outputSize: result.toBuffer().length, } satisfies CircuitSimulationStats); - return result; } } diff --git a/yarn-project/prover-client/src/tx-prover/tx-prover.ts b/yarn-project/prover-client/src/tx-prover/tx-prover.ts new file mode 100644 index 00000000000..782b65d14c2 --- /dev/null +++ b/yarn-project/prover-client/src/tx-prover/tx-prover.ts @@ -0,0 +1,73 @@ +import { ProcessedTx } from '@aztec/circuit-types'; +import { ProverClient, ProvingTicket } from '@aztec/circuit-types/interfaces'; +import { Fr, GlobalVariables } from '@aztec/circuits.js'; +import { SimulationProvider } from '@aztec/simulator'; +import { WorldStateSynchronizer } from '@aztec/world-state'; + +import { ProverConfig } from '../config.js'; +import { VerificationKeys, getVerificationKeys } from '../mocks/verification_keys.js'; +import { ProvingOrchestrator } from '../orchestrator/orchestrator.js'; +import { EmptyRollupProver } from '../prover/empty.js'; + +/** + * A prover accepting individual transaction requests + */ +export class TxProver implements ProverClient { + private orchestrator: ProvingOrchestrator; + constructor( + worldStateSynchronizer: WorldStateSynchronizer, + simulationProvider: SimulationProvider, + protected vks: VerificationKeys, + ) { + this.orchestrator = new ProvingOrchestrator( + worldStateSynchronizer.getLatest(), + simulationProvider, + getVerificationKeys(), + new EmptyRollupProver(), + ); + } + + /** + * Starts the prover instance + */ + public start() { + this.orchestrator.start(); + return Promise.resolve(); + } + + /** + * Stops the prover instance + */ + public async stop() { + await this.orchestrator.stop(); + } + + /** + * + * @param config - The prover configuration. + * @param worldStateSynchronizer - An instance of the world state + * @returns An instance of the prover, constructed and started. + */ + public static async new( + config: ProverConfig, + worldStateSynchronizer: WorldStateSynchronizer, + simulationProvider: SimulationProvider, + ) { + const prover = new TxProver(worldStateSynchronizer, simulationProvider, getVerificationKeys()); + await prover.start(); + return prover; + } + + public startNewBlock( + numTxs: number, + globalVariables: GlobalVariables, + newL1ToL2Messages: Fr[], + emptyTx: ProcessedTx, + ): Promise { + return this.orchestrator.startNewBlock(numTxs, globalVariables, newL1ToL2Messages, emptyTx); + } + + public addNewTx(tx: ProcessedTx): Promise { + return this.orchestrator.addNewTx(tx); + } +} diff --git a/yarn-project/prover-client/tsconfig.json b/yarn-project/prover-client/tsconfig.json index 63f8ab3e9f7..a9fab4069e1 100644 --- a/yarn-project/prover-client/tsconfig.json +++ b/yarn-project/prover-client/tsconfig.json @@ -6,8 +6,26 @@ "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ + { + "path": "../circuit-types" + }, + { + "path": "../circuits.js" + }, { "path": "../foundation" + }, + { + "path": "../kv-store" + }, + { + "path": "../noir-protocol-circuits-types" + }, + { + "path": "../simulator" + }, + { + "path": "../world-state" } ], "include": ["src"] diff --git a/yarn-project/sequencer-client/src/block_builder/index.ts b/yarn-project/sequencer-client/src/block_builder/index.ts deleted file mode 100644 index 7f2fefca322..00000000000 --- a/yarn-project/sequencer-client/src/block_builder/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { L2Block } from '@aztec/circuit-types'; -import { GlobalVariables, Proof } from '@aztec/circuits.js'; -import { Fr } from '@aztec/foundation/fields'; - -import { ProcessedTx } from '../sequencer/processed_tx.js'; - -/** - * Assembles an L2Block from a set of processed transactions. - */ -export interface BlockBuilder { - /** - * Creates a new L2Block with the given number, containing the set of processed txs. - * Note that the number of txs need to be a power of two. - * @param globalVariables - Global variables to include in the block. - * @param txs - Processed txs to include. - * @param l1ToL2Messages - L1 to L2 messages to be part of the block. - * @returns The new L2 block along with its proof from the root circuit. - */ - buildL2Block(globalVariables: GlobalVariables, txs: ProcessedTx[], l1ToL2Messages: Fr[]): Promise<[L2Block, Proof]>; -} diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts deleted file mode 100644 index 568dc8e56dc..00000000000 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ /dev/null @@ -1,453 +0,0 @@ -import { Body, L2Block, MerkleTreeId, Tx, TxEffect, makeEmptyLogs, mockTx } from '@aztec/circuit-types'; -import { - AppendOnlyTreeSnapshot, - AztecAddress, - BaseOrMergeRollupPublicInputs, - EthAddress, - Fr, - GlobalVariables, - Header, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_NEW_NOTE_HASHES_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - NULLIFIER_SUBTREE_HEIGHT, - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - PUBLIC_DATA_SUBTREE_HEIGHT, - PartialStateReference, - Proof, - PublicDataTreeLeaf, - PublicDataUpdateRequest, - PublicKernelCircuitPublicInputs, - RootRollupPublicInputs, - SideEffect, - SideEffectLinkedToNoteHash, - StateReference, - sideEffectCmp, -} from '@aztec/circuits.js'; -import { - fr, - makeBaseOrMergeRollupPublicInputs, - makeNewSideEffect, - makeNewSideEffectLinkedToNoteHash, - makeParityPublicInputs, - makePrivateKernelTailCircuitPublicInputs, - makeProof, - makePublicCallRequest, - makeRootRollupPublicInputs, -} from '@aztec/circuits.js/testing'; -import { makeTuple, range } from '@aztec/foundation/array'; -import { toBufferBE } from '@aztec/foundation/bigint-buffer'; -import { padArrayEnd, times } from '@aztec/foundation/collection'; -import { toTruncField } from '@aztec/foundation/serialize'; -import { openTmpStore } from '@aztec/kv-store/utils'; -import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; - -import { jest } from '@jest/globals'; -import { MockProxy, mock } from 'jest-mock-extended'; -import { type MemDown, default as memdown } from 'memdown'; - -import { VerificationKeys, getVerificationKeys } from '../mocks/verification_keys.js'; -import { EmptyRollupProver } from '../prover/empty.js'; -import { RollupProver } from '../prover/index.js'; -import { - ProcessedTx, - makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricalTreeRoots, - makeProcessedTx, - toTxEffect, -} from '../sequencer/processed_tx.js'; -import { WASMSimulator } from '../simulator/acvm_wasm.js'; -import { RollupSimulator } from '../simulator/index.js'; -import { RealRollupCircuitSimulator } from '../simulator/rollup.js'; -import { SoloBlockBuilder } from './solo_block_builder.js'; - -export const createMemDown = () => (memdown as any)() as MemDown; - -describe('sequencer/solo_block_builder', () => { - let builder: SoloBlockBuilder; - let builderDb: MerkleTreeOperations; - let expectsDb: MerkleTreeOperations; - let vks: VerificationKeys; - - let simulator: MockProxy; - let prover: MockProxy; - - let blockNumber: number; - let baseRollupOutputLeft: BaseOrMergeRollupPublicInputs; - let baseRollupOutputRight: BaseOrMergeRollupPublicInputs; - let rootRollupOutput: RootRollupPublicInputs; - let mockL1ToL2Messages: Fr[]; - - let globalVariables: GlobalVariables; - - const emptyProof = new Proof(Buffer.alloc(32, 0)); - - const chainId = Fr.ZERO; - const version = Fr.ZERO; - const coinbase = EthAddress.ZERO; - const feeRecipient = AztecAddress.ZERO; - - beforeEach(async () => { - blockNumber = 3; - globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO, coinbase, feeRecipient); - - builderDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); - expectsDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); - vks = getVerificationKeys(); - simulator = mock(); - prover = mock(); - builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); - - // Create mock l1 to L2 messages - mockL1ToL2Messages = new Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)); - - // Create mock outputs for simulator - baseRollupOutputLeft = makeBaseOrMergeRollupPublicInputs(0, globalVariables); - baseRollupOutputRight = makeBaseOrMergeRollupPublicInputs(0, globalVariables); - rootRollupOutput = makeRootRollupPublicInputs(0); - rootRollupOutput.header.globalVariables = globalVariables; - - // Set up mocks - prover.getBaseParityProof.mockResolvedValue(emptyProof); - prover.getRootParityProof.mockResolvedValue(emptyProof); - prover.getBaseRollupProof.mockResolvedValue(emptyProof); - prover.getRootRollupProof.mockResolvedValue(emptyProof); - simulator.baseParityCircuit - .mockResolvedValueOnce(makeParityPublicInputs(1)) - .mockResolvedValue(makeParityPublicInputs(2)) - .mockResolvedValue(makeParityPublicInputs(3)) - .mockResolvedValueOnce(makeParityPublicInputs(4)); - simulator.rootParityCircuit.mockResolvedValueOnce(makeParityPublicInputs(5)); - simulator.baseRollupCircuit - .mockResolvedValueOnce(baseRollupOutputLeft) - .mockResolvedValueOnce(baseRollupOutputRight); - simulator.rootRollupCircuit.mockResolvedValue(rootRollupOutput); - }, 20_000); - - const makeEmptyProcessedTx = async () => { - const header = await builderDb.buildInitialHeader(); - return makeEmptyProcessedTxFromHistoricalTreeRoots(header, chainId, version); - }; - - // Updates the expectedDb trees based on the new note hashes, contracts, and nullifiers from these txs - const updateExpectedTreesFromTxs = async (txs: ProcessedTx[]) => { - await expectsDb.appendLeaves( - MerkleTreeId.NOTE_HASH_TREE, - txs.flatMap(tx => - padArrayEnd( - [...tx.data.endNonRevertibleData.newNoteHashes, ...tx.data.end.newNoteHashes] - .filter(x => !x.isEmpty()) - .sort(sideEffectCmp), - SideEffect.empty(), - MAX_NEW_NOTE_HASHES_PER_TX, - ).map(l => l.value.toBuffer()), - ), - ); - await expectsDb.batchInsert( - MerkleTreeId.NULLIFIER_TREE, - txs.flatMap(tx => - padArrayEnd( - [...tx.data.endNonRevertibleData.newNullifiers, ...tx.data.end.newNullifiers] - .filter(x => !x.isEmpty()) - .sort(sideEffectCmp), - SideEffectLinkedToNoteHash.empty(), - MAX_NEW_NULLIFIERS_PER_TX, - ).map(x => x.value.toBuffer()), - ), - NULLIFIER_SUBTREE_HEIGHT, - ); - for (const tx of txs) { - await expectsDb.batchInsert( - MerkleTreeId.PUBLIC_DATA_TREE, - [...tx.data.endNonRevertibleData.publicDataUpdateRequests, ...tx.data.end.publicDataUpdateRequests].map( - write => { - return new PublicDataTreeLeaf(write.leafSlot, write.newValue).toBuffer(); - }, - ), - PUBLIC_DATA_SUBTREE_HEIGHT, - ); - } - }; - - const updateL1ToL2MessageTree = async (l1ToL2Messages: Fr[]) => { - const asBuffer = l1ToL2Messages.map(m => m.toBuffer()); - await expectsDb.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, asBuffer); - }; - - const updateArchive = async () => { - const blockHash = rootRollupOutput.header.hash(); - await expectsDb.appendLeaves(MerkleTreeId.ARCHIVE, [blockHash.toBuffer()]); - }; - - const getTreeSnapshot = async (tree: MerkleTreeId) => { - const treeInfo = await expectsDb.getTreeInfo(tree); - return new AppendOnlyTreeSnapshot(Fr.fromBuffer(treeInfo.root), Number(treeInfo.size)); - }; - - const getPartialStateReference = async () => { - return new PartialStateReference( - await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE), - await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE), - await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE), - ); - }; - - const getStateReference = async () => { - return new StateReference( - await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE), - await getPartialStateReference(), - ); - }; - - const buildMockSimulatorInputs = async () => { - const kernelOutput = makePrivateKernelTailCircuitPublicInputs(); - kernelOutput.constants.historicalHeader = await expectsDb.buildInitialHeader(); - kernelOutput.needsAppLogic = false; - kernelOutput.needsSetup = false; - kernelOutput.needsTeardown = false; - - const tx = makeProcessedTx( - new Tx( - kernelOutput, - emptyProof, - makeEmptyLogs(), - makeEmptyLogs(), - times(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makePublicCallRequest), - ), - ); - - const txs = [tx, await makeEmptyProcessedTx()]; - - // Calculate what would be the tree roots after the first tx and update mock circuit output - await updateExpectedTreesFromTxs([txs[0]]); - baseRollupOutputLeft.end = await getPartialStateReference(); - baseRollupOutputLeft.txsEffectsHash = toTruncField(toTxEffect(tx).hash()); - - // Same for the tx on the right - await updateExpectedTreesFromTxs([txs[1]]); - baseRollupOutputRight.end = await getPartialStateReference(); - baseRollupOutputRight.txsEffectsHash = toTruncField(toTxEffect(tx).hash()); - - // Update l1 to l2 message tree - await updateL1ToL2MessageTree(mockL1ToL2Messages); - - // Collect all new nullifiers, commitments, and contracts from all txs in this block - const txEffects: TxEffect[] = txs.map(tx => toTxEffect(tx)); - - const body = new Body(txEffects); - // We are constructing the block here just to get body hash/calldata hash so we can pass in an empty archive and header - const l2Block = L2Block.fromFields({ - archive: AppendOnlyTreeSnapshot.zero(), - header: Header.empty(), - // Only the values below go to body hash/calldata hash - body, - }); - - // Now we update can make the final header, compute the block hash and update archive - rootRollupOutput.header.globalVariables = globalVariables; - rootRollupOutput.header.contentCommitment.txsEffectsHash = l2Block.body.getTxsEffectsHash(); - rootRollupOutput.header.state = await getStateReference(); - - await updateArchive(); - rootRollupOutput.archive = await getTreeSnapshot(MerkleTreeId.ARCHIVE); - - return txs; - }; - - describe('mock simulator', () => { - beforeAll(() => { - jest.spyOn(TxEffect.prototype, 'hash').mockImplementation(() => { - return Buffer.alloc(32, 0); - }); - }); - - afterAll(() => { - jest.restoreAllMocks(); - }); - - beforeEach(() => { - // Create instance to test - builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); - // since we now assert on the hash of the tx effect while running the base rollup, - // we need to mock the hash function to return a constant value - }); - - it('builds an L2 block using mock simulator', async () => { - // Assemble a fake transaction - const txs = await buildMockSimulatorInputs(); - - // Actually build a block! - const [l2Block, proof] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); - - expect(l2Block.number).toEqual(blockNumber); - expect(proof).toEqual(emptyProof); - }, 20000); - - it('rejects if too many l1 to l2 messages are provided', async () => { - // Assemble a fake transaction - const txs = await buildMockSimulatorInputs(); - const l1ToL2Messages = new Array(100).fill(new Fr(0n)); - await expect(builder.buildL2Block(globalVariables, txs, l1ToL2Messages)).rejects.toThrow(); - }); - }); - - describe('circuits simulator', () => { - beforeEach(() => { - const simulator = new RealRollupCircuitSimulator(new WASMSimulator()); - const prover = new EmptyRollupProver(); - builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); - }); - - const makeBloatedProcessedTx = async (seed = 0x1) => { - seed *= MAX_NEW_NULLIFIERS_PER_TX; // Ensure no clashing given incremental seeds - const tx = mockTx(seed); - const kernelOutput = PublicKernelCircuitPublicInputs.empty(); - kernelOutput.constants.historicalHeader = await builderDb.buildInitialHeader(); - kernelOutput.end.publicDataUpdateRequests = makeTuple( - MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - i => new PublicDataUpdateRequest(fr(i), fr(i + 10)), - seed + 0x500, - ); - kernelOutput.endNonRevertibleData.publicDataUpdateRequests = makeTuple( - MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - i => new PublicDataUpdateRequest(fr(i), fr(i + 10)), - seed + 0x600, - ); - - const processedTx = makeProcessedTx(tx, kernelOutput, makeProof()); - - processedTx.data.end.newNoteHashes = makeTuple( - MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - makeNewSideEffect, - seed + 0x100, - ); - processedTx.data.endNonRevertibleData.newNoteHashes = makeTuple( - MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, - makeNewSideEffect, - seed + 0x100, - ); - processedTx.data.end.newNullifiers = makeTuple( - MAX_REVERTIBLE_NULLIFIERS_PER_TX, - makeNewSideEffectLinkedToNoteHash, - seed + 0x100000, - ); - - processedTx.data.endNonRevertibleData.newNullifiers = makeTuple( - MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - makeNewSideEffectLinkedToNoteHash, - seed + 0x100000 + MAX_REVERTIBLE_NULLIFIERS_PER_TX, - ); - - 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()); - - return processedTx; - }; - - it.each([ - [0, 4], - [1, 4], - [4, 4], - [0, 16], - [16, 16], - ] as const)( - 'builds an L2 block with %i bloated txs and %i txs total', - async (bloatedCount: number, totalCount: number) => { - const noteHashTreeBefore = await builderDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE); - const txs = [ - ...(await Promise.all(times(bloatedCount, makeBloatedProcessedTx))), - ...(await Promise.all(times(totalCount - bloatedCount, makeEmptyProcessedTx))), - ]; - - const [l2Block] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); - expect(l2Block.number).toEqual(blockNumber); - - await updateExpectedTreesFromTxs(txs); - const noteHashTreeAfter = await builderDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE); - - if (bloatedCount > 0) { - expect(noteHashTreeAfter.root).not.toEqual(noteHashTreeBefore.root); - } - - const expectedNoteHashTreeAfter = await expectsDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE).then(t => t.root); - expect(noteHashTreeAfter.root).toEqual(expectedNoteHashTreeAfter); - }, - 60000, - ); - - it('builds an empty L2 block', async () => { - const txs = await Promise.all([ - makeEmptyProcessedTx(), - makeEmptyProcessedTx(), - makeEmptyProcessedTx(), - makeEmptyProcessedTx(), - ]); - - const [l2Block] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); - expect(l2Block.number).toEqual(blockNumber); - }, 30_000); - - it('builds a mixed L2 block', async () => { - const txs = await Promise.all([ - makeBloatedProcessedTx(1), - makeBloatedProcessedTx(2), - makeBloatedProcessedTx(3), - makeBloatedProcessedTx(4), - ]); - - const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); - - const [l2Block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); - expect(l2Block.number).toEqual(blockNumber); - }, 200_000); - - // This test specifically tests nullifier values which previously caused e2e_private_token test to fail - it('e2e_private_token edge case regression test on nullifier values', async () => { - const simulator = new RealRollupCircuitSimulator(new WASMSimulator()); - const prover = new EmptyRollupProver(); - builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); - // update the starting tree - const updateVals = Array(4 * MAX_NEW_NULLIFIERS_PER_TX).fill(0n); - updateVals[0] = 19777494491628650244807463906174285795660759352776418619064841306523677458742n; - updateVals[1] = 10246291467305176436335175657884940686778521321101740385288169037814567547848n; - - // new added values - const tx = await makeEmptyProcessedTx(); - tx.data.end.newNullifiers[0] = new SideEffectLinkedToNoteHash( - new Fr(10336601644835972678500657502133589897705389664587188571002640950065546264856n), - Fr.ZERO, - Fr.ZERO, - ); - tx.data.end.newNullifiers[1] = new SideEffectLinkedToNoteHash( - new Fr(17490072961923661940560522096125238013953043065748521735636170028491723851741n), - Fr.ZERO, - Fr.ZERO, - ); - - const txs = [tx, await makeEmptyProcessedTx(), await makeEmptyProcessedTx(), await makeEmptyProcessedTx()]; - - // Must be built after the txs are created - await builderDb.batchInsert( - MerkleTreeId.NULLIFIER_TREE, - updateVals.map(v => toBufferBE(v, 32)), - NULLIFIER_SUBTREE_HEIGHT, - ); - - const [l2Block] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); - - expect(l2Block.number).toEqual(blockNumber); - }, 20000); - }); - - // describe("Input guard tests", () => { - // }) -}); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts deleted file mode 100644 index 48acbde1230..00000000000 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ /dev/null @@ -1,812 +0,0 @@ -import { Body, L2Block, MerkleTreeId, TxEffect } from '@aztec/circuit-types'; -import { CircuitSimulationStats } from '@aztec/circuit-types/stats'; -import { - ARCHIVE_HEIGHT, - AppendOnlyTreeSnapshot, - BaseOrMergeRollupPublicInputs, - BaseParityInputs, - BaseRollupInputs, - ConstantRollupData, - GlobalVariables, - L1_TO_L2_MSG_SUBTREE_HEIGHT, - L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MembershipWitness, - MergeRollupInputs, - NOTE_HASH_SUBTREE_HEIGHT, - NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_SUBTREE_HEIGHT, - NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_TREE_HEIGHT, - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - NUM_BASE_PARITY_PER_ROOT_PARITY, - NullifierLeafPreimage, - PUBLIC_DATA_SUBTREE_HEIGHT, - PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, - PUBLIC_DATA_TREE_HEIGHT, - PartialStateReference, - PreviousRollupData, - Proof, - PublicDataTreeLeaf, - PublicDataTreeLeafPreimage, - ROLLUP_VK_TREE_HEIGHT, - RollupKernelCircuitPublicInputs, - RollupKernelData, - RollupTypes, - RootParityInput, - RootParityInputs, - RootRollupInputs, - RootRollupPublicInputs, - StateDiffHints, - StateReference, - VK_TREE_HEIGHT, - VerificationKey, -} from '@aztec/circuits.js'; -import { assertPermutation, makeTuple } from '@aztec/foundation/array'; -import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; -import { padArrayEnd } from '@aztec/foundation/collection'; -import { Fr } from '@aztec/foundation/fields'; -import { createDebugLogger } from '@aztec/foundation/log'; -import { Tuple, assertLength, toFriendlyJSON } from '@aztec/foundation/serialize'; -import { elapsed } from '@aztec/foundation/timer'; -import { MerkleTreeOperations } from '@aztec/world-state'; - -import chunk from 'lodash.chunk'; -import { inspect } from 'util'; - -import { VerificationKeys } from '../mocks/verification_keys.js'; -import { RollupProver } from '../prover/index.js'; -import { ProcessedTx, toTxEffect } from '../sequencer/processed_tx.js'; -import { RollupSimulator } from '../simulator/index.js'; -import { BlockBuilder } from './index.js'; -import { TreeNames } from './types.js'; - -const frToBigInt = (fr: Fr) => toBigIntBE(fr.toBuffer()); - -// Denotes fields that are not used now, but will be in the future -const FUTURE_FR = new Fr(0n); -const FUTURE_NUM = 0; - -// Denotes fields that should be deleted -const DELETE_FR = new Fr(0n); - -/** - * Builds an L2 block out of a set of ProcessedTx's, - * using the base, merge, and root rollup circuits. - */ -export class SoloBlockBuilder implements BlockBuilder { - constructor( - protected db: MerkleTreeOperations, - protected vks: VerificationKeys, - protected simulator: RollupSimulator, - protected prover: RollupProver, - protected debug = createDebugLogger('aztec:sequencer:solo-block-builder'), - ) {} - - /** - * Builds an L2 block with the given number containing the given txs, updating state trees. - * @param globalVariables - Global variables to be used in the block. - * @param txs - Processed transactions to include in the block. - * @param l1ToL2Messages - L1 to L2 messages to be part of the block. - * @param timestamp - Timestamp of the block. - * @returns The new L2 block and a correctness proof as returned by the root rollup circuit. - */ - public async buildL2Block( - globalVariables: GlobalVariables, - txs: ProcessedTx[], - l1ToL2Messages: Fr[], - ): Promise<[L2Block, Proof]> { - // Check txs are good for processing by checking if all the tree snapshots in header are non-empty - this.validateTxs(txs); - - // We fill the tx batch with empty txs, we process only one tx at a time for now - const [circuitsOutput, proof] = await this.runCircuits(globalVariables, txs, l1ToL2Messages); - - // Collect all new nullifiers, commitments, and contracts from all txs in this block - const txEffects: TxEffect[] = txs.map(tx => toTxEffect(tx)); - - const blockBody = new Body(txEffects); - - const l2Block = L2Block.fromFields({ - archive: circuitsOutput.archive, - header: circuitsOutput.header, - body: blockBody, - }); - - if (!l2Block.body.getTxsEffectsHash().equals(circuitsOutput.header.contentCommitment.txsEffectsHash)) { - this.debug(inspect(blockBody)); - throw new Error( - `Txs effects hash mismatch, ${l2Block.body - .getTxsEffectsHash() - .toString('hex')} == ${circuitsOutput.header.contentCommitment.txsEffectsHash.toString('hex')} `, - ); - } - - return [l2Block, proof]; - } - - protected validateTxs(txs: ProcessedTx[]) { - for (const tx of txs) { - const txHeader = tx.data.constants.historicalHeader; - if (txHeader.state.l1ToL2MessageTree.isZero()) { - throw new Error(`Empty L1 to L2 messages tree in tx: ${toFriendlyJSON(tx)}`); - } - if (txHeader.state.partial.noteHashTree.isZero()) { - throw new Error(`Empty note hash tree in tx: ${toFriendlyJSON(tx)}`); - } - if (txHeader.state.partial.nullifierTree.isZero()) { - throw new Error(`Empty nullifier tree in tx: ${toFriendlyJSON(tx)}`); - } - if (txHeader.state.partial.publicDataTree.isZero()) { - throw new Error(`Empty public data tree in tx: ${toFriendlyJSON(tx)}`); - } - } - } - - protected async getTreeSnapshot(id: MerkleTreeId): Promise { - const treeInfo = await this.db.getTreeInfo(id); - return new AppendOnlyTreeSnapshot(Fr.fromBuffer(treeInfo.root), Number(treeInfo.size)); - } - - protected async runCircuits( - globalVariables: GlobalVariables, - txs: ProcessedTx[], - l1ToL2Messages: Fr[], - ): Promise<[RootRollupPublicInputs, Proof]> { - // TODO(#5357): Instead of performing the check bellow pad the txs here. - // Check that the length of the array of txs is a power of two - // See https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 - if (txs.length < 2 || (txs.length & (txs.length - 1)) !== 0) { - throw new Error(`Length of txs for the block should be a power of two and at least two (got ${txs.length})`); - } - - // We pad the messages as the circuits expect that. - const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); - - // BASE PARITY CIRCUIT (run in parallel) - // Note: In the future we will want to cache the results of empty base and root parity circuits so that we don't - // have to run them. (It will most likely be quite common that some base parity circuits will be "empty") - let baseParityInputs: BaseParityInputs[] = []; - let elapsedBaseParityOutputsPromise: Promise<[number, RootParityInput[]]>; - { - baseParityInputs = Array.from({ length: NUM_BASE_PARITY_PER_ROOT_PARITY }, (_, i) => - BaseParityInputs.fromSlice(l1ToL2MessagesPadded, i), - ); - - const baseParityOutputs: Promise[] = []; - for (const inputs of baseParityInputs) { - baseParityOutputs.push(this.baseParityCircuit(inputs)); - } - elapsedBaseParityOutputsPromise = elapsed(() => Promise.all(baseParityOutputs)); - } - - // BASE ROLLUP CIRCUIT (run in parallel) - let elapsedBaseRollupOutputsPromise: Promise<[number, [BaseOrMergeRollupPublicInputs, Proof][]]>; - const baseRollupInputs: BaseRollupInputs[] = []; - { - // Perform all tree insertions and retrieve snapshots for all base rollups - const treeSnapshots: Map[] = []; - for (const tx of txs) { - const input = await this.buildBaseRollupInput(tx, globalVariables); - baseRollupInputs.push(input); - const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map( - async (id: MerkleTreeId) => { - return { key: id, value: await this.getTreeSnapshot(id) }; - }, - ); - const snapshots: Map = new Map( - (await Promise.all(promises)).map(obj => [obj.key, obj.value]), - ); - treeSnapshots.push(snapshots); - } - - // Run the base rollup circuits for the txs in parallel - const baseRollupOutputs: Promise<[BaseOrMergeRollupPublicInputs, Proof]>[] = []; - for (let i = 0; i < txs.length; i++) { - baseRollupOutputs.push(this.baseRollupCircuit(txs[i], baseRollupInputs[i], treeSnapshots[i])); - } - - elapsedBaseRollupOutputsPromise = elapsed(() => Promise.all(baseRollupOutputs)); - } - - // ROOT PARITY CIRCUIT - let elapsedRootParityOutputPromise: Promise<[number, RootParityInput]>; - let rootParityInputs: RootParityInputs; - { - // First we await the base parity outputs - const [duration, baseParityOutputs] = await elapsedBaseParityOutputsPromise; - - // We emit stats for base parity circuits - for (let i = 0; i < baseParityOutputs.length; i++) { - this.debug(`Simulated base parity circuit`, { - eventName: 'circuit-simulation', - circuitName: 'base-parity', - duration: duration / baseParityOutputs.length, - inputSize: baseParityInputs[i].toBuffer().length, - outputSize: baseParityOutputs[i].toBuffer().length, - } satisfies CircuitSimulationStats); - } - - rootParityInputs = new RootParityInputs( - baseParityOutputs as Tuple, - ); - elapsedRootParityOutputPromise = elapsed(() => this.rootParityCircuit(rootParityInputs)); - } - - // MERGE ROLLUP CIRCUIT (each layer run in parallel) - let mergeOutputLeft: [BaseOrMergeRollupPublicInputs, Proof]; - let mergeOutputRight: [BaseOrMergeRollupPublicInputs, Proof]; - { - // Run merge rollups in layers until we have only two outputs - const [duration, mergeInputs] = await elapsedBaseRollupOutputsPromise; - - // We emit stats for base rollup circuits - for (let i = 0; i < mergeInputs.length; i++) { - this.debug(`Simulated base rollup circuit`, { - eventName: 'circuit-simulation', - circuitName: 'base-rollup', - duration: duration / mergeInputs.length, - inputSize: baseRollupInputs[i].toBuffer().length, - outputSize: mergeInputs[i][0].toBuffer().length, - } satisfies CircuitSimulationStats); - } - - let mergeRollupInputs: [BaseOrMergeRollupPublicInputs, Proof][] = mergeInputs; - while (mergeRollupInputs.length > 2) { - const mergeInputStructs: MergeRollupInputs[] = []; - for (const pair of chunk(mergeRollupInputs, 2)) { - const [r1, r2] = pair; - mergeInputStructs.push(this.createMergeRollupInputs(r1, r2)); - } - - const [duration, mergeOutputs] = await elapsed(() => - Promise.all(mergeInputStructs.map(async input => await this.mergeRollupCircuit(input))), - ); - - // We emit stats for merge rollup circuits - for (let i = 0; i < mergeOutputs.length; i++) { - this.debug(`Simulated merge rollup circuit`, { - eventName: 'circuit-simulation', - circuitName: 'merge-rollup', - duration: duration / mergeOutputs.length, - inputSize: mergeInputStructs[i].toBuffer().length, - outputSize: mergeOutputs[i][0].toBuffer().length, - } satisfies CircuitSimulationStats); - } - mergeRollupInputs = mergeOutputs; - } - - // Run the root rollup with the last two merge rollups (or base, if no merge layers) - [mergeOutputLeft, mergeOutputRight] = mergeRollupInputs; - } - - // Finally, we emit stats for root parity circuit - const [duration, rootParityOutput] = await elapsedRootParityOutputPromise; - this.debug(`Simulated root parity circuit`, { - eventName: 'circuit-simulation', - circuitName: 'root-parity', - duration: duration, - inputSize: rootParityInputs.toBuffer().length, - outputSize: rootParityOutput.toBuffer().length, - } satisfies CircuitSimulationStats); - - return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, rootParityOutput, l1ToL2MessagesPadded); - } - - protected async baseParityCircuit(inputs: BaseParityInputs): Promise { - this.debug(`Running base parity circuit`); - const parityPublicInputs = await this.simulator.baseParityCircuit(inputs); - const proof = await this.prover.getBaseParityProof(inputs, parityPublicInputs); - return new RootParityInput(proof, parityPublicInputs); - } - - protected async rootParityCircuit(inputs: RootParityInputs): Promise { - this.debug(`Running root parity circuit`); - const parityPublicInputs = await this.simulator.rootParityCircuit(inputs); - const proof = await this.prover.getRootParityProof(inputs, parityPublicInputs); - return new RootParityInput(proof, parityPublicInputs); - } - - protected async baseRollupCircuit( - tx: ProcessedTx, - inputs: BaseRollupInputs, - treeSnapshots: Map, - ): Promise<[BaseOrMergeRollupPublicInputs, Proof]> { - this.debug(`Running base rollup for ${tx.hash}`); - const rollupOutput = await this.simulator.baseRollupCircuit(inputs); - this.validatePartialState(rollupOutput.end, treeSnapshots); - const proof = await this.prover.getBaseRollupProof(inputs, rollupOutput); - return [rollupOutput, proof]; - } - - protected createMergeRollupInputs( - left: [BaseOrMergeRollupPublicInputs, Proof], - right: [BaseOrMergeRollupPublicInputs, Proof], - ) { - const vk = this.getVerificationKey(left[0].rollupType); - const mergeInputs = new MergeRollupInputs([ - this.getPreviousRollupDataFromPublicInputs(left[0], left[1], vk), - this.getPreviousRollupDataFromPublicInputs(right[0], right[1], vk), - ]); - return mergeInputs; - } - - protected async mergeRollupCircuit(mergeInputs: MergeRollupInputs): Promise<[BaseOrMergeRollupPublicInputs, Proof]> { - this.debug(`Running merge rollup circuit`); - const output = await this.simulator.mergeRollupCircuit(mergeInputs); - const proof = await this.prover.getMergeRollupProof(mergeInputs, output); - return [output, proof]; - } - - protected getVerificationKey(type: RollupTypes) { - switch (type) { - case RollupTypes.Base: - return this.vks.baseRollupCircuit; - case RollupTypes.Merge: - return this.vks.mergeRollupCircuit; - default: - throw new Error(`No verification key available for ${type}`); - } - } - - protected async rootRollupCircuit( - left: [BaseOrMergeRollupPublicInputs, Proof], - right: [BaseOrMergeRollupPublicInputs, Proof], - l1ToL2Roots: RootParityInput, - l1ToL2Messages: Tuple, - ): Promise<[RootRollupPublicInputs, Proof]> { - this.debug(`Running root rollup circuit`); - const rootInput = await this.getRootRollupInput(...left, ...right, l1ToL2Roots, l1ToL2Messages); - - // Update the local trees to include the l1 to l2 messages - await this.db.appendLeaves( - MerkleTreeId.L1_TO_L2_MESSAGE_TREE, - l1ToL2Messages.map(m => m.toBuffer()), - ); - - // Simulate and get proof for the root circuit - const rootOutput = await this.simulator.rootRollupCircuit(rootInput); - - const rootProof = await this.prover.getRootRollupProof(rootInput, rootOutput); - - this.debug(`Updating archive with new header`); - await this.db.updateArchive(rootOutput.header); - - await this.validateRootOutput(rootOutput); - - return [rootOutput, rootProof]; - } - - protected validatePartialState( - partialState: PartialStateReference, - treeSnapshots: Map, - ) { - this.validateSimulatedTree( - treeSnapshots.get(MerkleTreeId.NOTE_HASH_TREE)!, - partialState.noteHashTree, - 'NoteHashTree', - ); - this.validateSimulatedTree( - treeSnapshots.get(MerkleTreeId.NULLIFIER_TREE)!, - partialState.nullifierTree, - 'NullifierTree', - ); - this.validateSimulatedTree( - treeSnapshots.get(MerkleTreeId.PUBLIC_DATA_TREE)!, - partialState.publicDataTree, - 'PublicDataTree', - ); - } - - protected async validateState(state: StateReference) { - const promises = [MerkleTreeId.NOTE_HASH_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.PUBLIC_DATA_TREE].map( - async (id: MerkleTreeId) => { - return { key: id, value: await this.getTreeSnapshot(id) }; - }, - ); - const snapshots: Map = new Map( - (await Promise.all(promises)).map(obj => [obj.key, obj.value]), - ); - this.validatePartialState(state.partial, snapshots); - this.validateSimulatedTree( - await this.getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE), - state.l1ToL2MessageTree, - 'L1ToL2MessageTree', - ); - } - - // Validate that the roots of all local trees match the output of the root circuit simulation - protected async validateRootOutput(rootOutput: RootRollupPublicInputs) { - await Promise.all([ - this.validateState(rootOutput.header.state), - this.validateSimulatedTree(await this.getTreeSnapshot(MerkleTreeId.ARCHIVE), rootOutput.archive, 'Archive'), - ]); - } - - // Helper for comparing two trees snapshots - protected validateSimulatedTree( - localTree: AppendOnlyTreeSnapshot, - simulatedTree: AppendOnlyTreeSnapshot, - name: TreeNames, - label?: string, - ) { - if (!simulatedTree.root.toBuffer().equals(localTree.root.toBuffer())) { - throw new Error(`${label ?? name} tree root mismatch (local ${localTree.root}, simulated ${simulatedTree.root})`); - } - if (simulatedTree.nextAvailableLeafIndex !== localTree.nextAvailableLeafIndex) { - throw new Error( - `${label ?? name} tree next available leaf index mismatch (local ${ - localTree.nextAvailableLeafIndex - }, simulated ${simulatedTree.nextAvailableLeafIndex})`, - ); - } - } - - // Builds the inputs for the root rollup circuit, without making any changes to trees - protected async getRootRollupInput( - rollupOutputLeft: BaseOrMergeRollupPublicInputs, - rollupProofLeft: Proof, - rollupOutputRight: BaseOrMergeRollupPublicInputs, - rollupProofRight: Proof, - l1ToL2Roots: RootParityInput, - newL1ToL2Messages: Tuple, - ) { - const vk = this.getVerificationKey(rollupOutputLeft.rollupType); - const previousRollupData: RootRollupInputs['previousRollupData'] = [ - this.getPreviousRollupDataFromPublicInputs(rollupOutputLeft, rollupProofLeft, vk), - this.getPreviousRollupDataFromPublicInputs(rollupOutputRight, rollupProofRight, vk), - ]; - - const getRootTreeSiblingPath = async (treeId: MerkleTreeId) => { - const { size } = await this.db.getTreeInfo(treeId); - const path = await this.db.getSiblingPath(treeId, size); - return path.toFields(); - }; - - const newL1ToL2MessageTreeRootSiblingPathArray = await this.getSubtreeSiblingPath( - MerkleTreeId.L1_TO_L2_MESSAGE_TREE, - L1_TO_L2_MSG_SUBTREE_HEIGHT, - ); - - const newL1ToL2MessageTreeRootSiblingPath = makeTuple( - L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, - i => - i < newL1ToL2MessageTreeRootSiblingPathArray.length ? newL1ToL2MessageTreeRootSiblingPathArray[i] : Fr.ZERO, - 0, - ); - - // Get tree snapshots - const startL1ToL2MessageTreeSnapshot = await this.getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE); - - // Get blocks tree - const startArchiveSnapshot = await this.getTreeSnapshot(MerkleTreeId.ARCHIVE); - const newArchiveSiblingPathArray = await getRootTreeSiblingPath(MerkleTreeId.ARCHIVE); - - const newArchiveSiblingPath = makeTuple( - ARCHIVE_HEIGHT, - i => (i < newArchiveSiblingPathArray.length ? newArchiveSiblingPathArray[i] : Fr.ZERO), - 0, - ); - - return RootRollupInputs.from({ - previousRollupData, - l1ToL2Roots, - newL1ToL2Messages, - newL1ToL2MessageTreeRootSiblingPath, - startL1ToL2MessageTreeSnapshot, - startArchiveSnapshot, - newArchiveSiblingPath, - }); - } - - protected getPreviousRollupDataFromPublicInputs( - rollupOutput: BaseOrMergeRollupPublicInputs, - rollupProof: Proof, - vk: VerificationKey, - ) { - return new PreviousRollupData( - rollupOutput, - rollupProof, - vk, - - // MembershipWitness for a VK tree to be implemented in the future - FUTURE_NUM, - new MembershipWitness( - ROLLUP_VK_TREE_HEIGHT, - BigInt(FUTURE_NUM), - makeTuple(ROLLUP_VK_TREE_HEIGHT, () => FUTURE_FR), - ), - ); - } - - protected getKernelDataFor(tx: ProcessedTx): RollupKernelData { - const inputs = new RollupKernelCircuitPublicInputs( - tx.data.aggregationObject, - tx.data.combinedData, - tx.data.constants, - ); - return new RollupKernelData( - inputs, - tx.proof, - - // VK for the kernel circuit - this.vks.privateKernelCircuit, - - // MembershipWitness for a VK tree to be implemented in the future - FUTURE_NUM, - assertLength(Array(VK_TREE_HEIGHT).fill(FUTURE_FR), VK_TREE_HEIGHT), - ); - } - - // Scan a tree searching for a specific value and return a membership witness proof for it - protected async getMembershipWitnessFor( - value: Fr, - treeId: MerkleTreeId, - height: N, - ): Promise> { - // If this is an empty tx, then just return zeroes - if (value.isZero()) { - return this.makeEmptyMembershipWitness(height); - } - - const index = await this.db.findLeafIndex(treeId, value.toBuffer()); - if (index === undefined) { - throw new Error(`Leaf with value ${value} not found in tree ${MerkleTreeId[treeId]}`); - } - const path = await this.db.getSiblingPath(treeId, index); - return new MembershipWitness(height, index, assertLength(path.toFields(), height)); - } - - protected async getConstantRollupData(globalVariables: GlobalVariables): Promise { - return ConstantRollupData.from({ - baseRollupVkHash: DELETE_FR, - mergeRollupVkHash: DELETE_FR, - privateKernelVkTreeRoot: FUTURE_FR, - publicKernelVkTreeRoot: FUTURE_FR, - lastArchive: await this.getTreeSnapshot(MerkleTreeId.ARCHIVE), - globalVariables, - }); - } - - protected async getLowNullifierInfo(nullifier: Fr) { - // Return empty nullifier info for an empty tx - if (nullifier.value === 0n) { - return { - index: 0, - leafPreimage: NullifierLeafPreimage.empty(), - witness: this.makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), - }; - } - - const tree = MerkleTreeId.NULLIFIER_TREE; - const prevValueIndex = await this.db.getPreviousValueIndex(tree, frToBigInt(nullifier)); - if (!prevValueIndex) { - throw new Error(`Nullifier tree should have one initial leaf`); - } - const prevValuePreimage = (await this.db.getLeafPreimage(tree, prevValueIndex.index))!; - - const prevValueSiblingPath = await this.db.getSiblingPath(tree, BigInt(prevValueIndex.index)); - - return { - index: prevValueIndex, - leafPreimage: prevValuePreimage, - witness: new MembershipWitness( - NULLIFIER_TREE_HEIGHT, - BigInt(prevValueIndex.index), - assertLength(prevValueSiblingPath.toFields(), NULLIFIER_TREE_HEIGHT), - ), - }; - } - - protected async getSubtreeSiblingPath(treeId: MerkleTreeId, subtreeHeight: number): Promise { - const nextAvailableLeafIndex = await this.db.getTreeInfo(treeId).then(t => t.size); - const fullSiblingPath = await this.db.getSiblingPath(treeId, nextAvailableLeafIndex); - - // Drop the first subtreeHeight items since we only care about the path to the subtree root - return fullSiblingPath.getSubtreeSiblingPath(subtreeHeight).toFields(); - } - - protected async processPublicDataUpdateRequests(tx: ProcessedTx) { - const combinedPublicDataUpdateRequests = tx.data.combinedData.publicDataUpdateRequests.map(updateRequest => { - return new PublicDataTreeLeaf(updateRequest.leafSlot, updateRequest.newValue); - }); - const { lowLeavesWitnessData, newSubtreeSiblingPath, sortedNewLeaves, sortedNewLeavesIndexes } = - await this.db.batchInsert( - MerkleTreeId.PUBLIC_DATA_TREE, - combinedPublicDataUpdateRequests.map(x => x.toBuffer()), - // TODO(#3675) remove oldValue from update requests - PUBLIC_DATA_SUBTREE_HEIGHT, - ); - - if (lowLeavesWitnessData === undefined) { - throw new Error(`Could not craft public data batch insertion proofs`); - } - - const sortedPublicDataWrites = makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { - return PublicDataTreeLeaf.fromBuffer(sortedNewLeaves[i]); - }); - - const sortedPublicDataWritesIndexes = makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { - return sortedNewLeavesIndexes[i]; - }); - - const subtreeSiblingPathAsFields = newSubtreeSiblingPath.toFields(); - const newPublicDataSubtreeSiblingPath = makeTuple(PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, i => { - return subtreeSiblingPathAsFields[i]; - }); - - const lowPublicDataWritesMembershipWitnesses: Tuple< - MembershipWitness, - typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX - > = makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { - const witness = lowLeavesWitnessData[i]; - return MembershipWitness.fromBufferArray( - witness.index, - assertLength(witness.siblingPath.toBufferArray(), PUBLIC_DATA_TREE_HEIGHT), - ); - }); - - const lowPublicDataWritesPreimages: Tuple< - PublicDataTreeLeafPreimage, - typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX - > = makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => { - return lowLeavesWitnessData[i].leafPreimage as PublicDataTreeLeafPreimage; - }); - - // validate that the sortedPublicDataWrites and sortedPublicDataWritesIndexes are in the correct order - // otherwise it will just fail in the circuit - assertPermutation(combinedPublicDataUpdateRequests, sortedPublicDataWrites, sortedPublicDataWritesIndexes, (a, b) => - a.equals(b), - ); - - return { - lowPublicDataWritesPreimages, - lowPublicDataWritesMembershipWitnesses, - newPublicDataSubtreeSiblingPath, - sortedPublicDataWrites, - sortedPublicDataWritesIndexes, - }; - } - - protected async getPublicDataReadsInfo(tx: ProcessedTx) { - const newPublicDataReadsWitnesses: Tuple< - MembershipWitness, - typeof MAX_PUBLIC_DATA_READS_PER_TX - > = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT, 0n)); - - const newPublicDataReadsPreimages: Tuple = - makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PublicDataTreeLeafPreimage.empty()); - - for (const i in tx.data.validationRequests.publicDataReads) { - const leafSlot = tx.data.validationRequests.publicDataReads[i].leafSlot.value; - const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot); - if (!lowLeafResult) { - throw new Error(`Public data tree should have one initial leaf`); - } - const preimage = await this.db.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index); - const path = await this.db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index); - newPublicDataReadsWitnesses[i] = new MembershipWitness( - PUBLIC_DATA_TREE_HEIGHT, - BigInt(lowLeafResult.index), - path.toTuple(), - ); - newPublicDataReadsPreimages[i] = preimage! as PublicDataTreeLeafPreimage; - } - return { - newPublicDataReadsWitnesses, - newPublicDataReadsPreimages, - }; - } - - // Builds the base rollup inputs, updating the contract, nullifier, and data trees in the process - protected async buildBaseRollupInput(tx: ProcessedTx, globalVariables: GlobalVariables) { - // Get trees info before any changes hit - const constants = await this.getConstantRollupData(globalVariables); - const start = new PartialStateReference( - await this.getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE), - await this.getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE), - await this.getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE), - ); - - // Get the subtree sibling paths for the circuit - const noteHashSubtreeSiblingPathArray = await this.getSubtreeSiblingPath( - MerkleTreeId.NOTE_HASH_TREE, - NOTE_HASH_SUBTREE_HEIGHT, - ); - - const noteHashSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, i => - i < noteHashSubtreeSiblingPathArray.length ? noteHashSubtreeSiblingPathArray[i] : Fr.ZERO, - ); - - // Update the note hash trees with the new items being inserted to get the new roots - // that will be used by the next iteration of the base rollup circuit, skipping the empty ones - const newNoteHashes = tx.data.combinedData.newNoteHashes.map(x => x.value.toBuffer()); - await this.db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, newNoteHashes); - - // The read witnesses for a given TX should be generated before the writes of the same TX are applied. - // All reads that refer to writes in the same tx are transient and can be simplified out. - const txPublicDataReadsInfo = await this.getPublicDataReadsInfo(tx); - const txPublicDataUpdateRequestInfo = await this.processPublicDataUpdateRequests(tx); - - // Update the nullifier tree, capturing the low nullifier info for each individual operation - const { - lowLeavesWitnessData: nullifierWitnessLeaves, - newSubtreeSiblingPath: newNullifiersSubtreeSiblingPath, - sortedNewLeaves: sortedNewNullifiers, - sortedNewLeavesIndexes, - } = await this.db.batchInsert( - MerkleTreeId.NULLIFIER_TREE, - tx.data.combinedData.newNullifiers.map(sideEffectLinkedToNoteHash => sideEffectLinkedToNoteHash.value.toBuffer()), - NULLIFIER_SUBTREE_HEIGHT, - ); - if (nullifierWitnessLeaves === undefined) { - throw new Error(`Could not craft nullifier batch insertion proofs`); - } - - // Extract witness objects from returned data - const nullifierPredecessorMembershipWitnessesWithoutPadding: MembershipWitness[] = - nullifierWitnessLeaves.map(l => - MembershipWitness.fromBufferArray(l.index, assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT)), - ); - - const nullifierSubtreeSiblingPathArray = newNullifiersSubtreeSiblingPath.toFields(); - - const nullifierSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, i => - i < nullifierSubtreeSiblingPathArray.length ? nullifierSubtreeSiblingPathArray[i] : Fr.ZERO, - ); - - const publicDataSiblingPath = txPublicDataUpdateRequestInfo.newPublicDataSubtreeSiblingPath; - - const stateDiffHints = StateDiffHints.from({ - nullifierPredecessorPreimages: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => - i < nullifierWitnessLeaves.length - ? (nullifierWitnessLeaves[i].leafPreimage as NullifierLeafPreimage) - : NullifierLeafPreimage.empty(), - ), - nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => - i < nullifierPredecessorMembershipWitnessesWithoutPadding.length - ? nullifierPredecessorMembershipWitnessesWithoutPadding[i] - : this.makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), - ), - sortedNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortedNewNullifiers[i])), - sortedNullifierIndexes: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), - noteHashSubtreeSiblingPath, - nullifierSubtreeSiblingPath, - publicDataSiblingPath, - }); - - const blockHash = tx.data.constants.historicalHeader.hash(); - const archiveRootMembershipWitness = await this.getMembershipWitnessFor( - blockHash, - MerkleTreeId.ARCHIVE, - ARCHIVE_HEIGHT, - ); - - return BaseRollupInputs.from({ - kernelData: this.getKernelDataFor(tx), - start, - stateDiffHints, - - sortedPublicDataWrites: txPublicDataUpdateRequestInfo.sortedPublicDataWrites, - sortedPublicDataWritesIndexes: txPublicDataUpdateRequestInfo.sortedPublicDataWritesIndexes, - lowPublicDataWritesPreimages: txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages, - lowPublicDataWritesMembershipWitnesses: txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses, - publicDataReadsPreimages: txPublicDataReadsInfo.newPublicDataReadsPreimages, - publicDataReadsMembershipWitnesses: txPublicDataReadsInfo.newPublicDataReadsWitnesses, - - archiveRootMembershipWitness, - - constants, - }); - } - - protected makeEmptyMembershipWitness(height: N) { - return new MembershipWitness( - height, - 0n, - makeTuple(height, () => Fr.ZERO), - ); - } -} diff --git a/yarn-project/sequencer-client/src/block_builder/types.ts b/yarn-project/sequencer-client/src/block_builder/types.ts deleted file mode 100644 index b687864c69d..00000000000 --- a/yarn-project/sequencer-client/src/block_builder/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Type representing the names of the trees for the base rollup. - */ -type BaseTreeNames = 'NoteHashTree' | 'ContractTree' | 'NullifierTree' | 'PublicDataTree'; -/** - * Type representing the names of the trees. - */ -export type TreeNames = BaseTreeNames | 'L1ToL2MessageTree' | 'Archive'; diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index b85130d5716..ba7ab1ec918 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -1,45 +1,15 @@ import { L1ToL2MessageSource, L2BlockSource } from '@aztec/circuit-types'; -import { createDebugLogger } from '@aztec/foundation/log'; +import { BlockProver } from '@aztec/circuit-types/interfaces'; import { P2P } from '@aztec/p2p'; +import { SimulationProvider } from '@aztec/simulator'; import { ContractDataSource } from '@aztec/types/contracts'; import { WorldStateSynchronizer } from '@aztec/world-state'; -import * as fs from 'fs/promises'; - -import { SoloBlockBuilder } from '../block_builder/solo_block_builder.js'; import { SequencerClientConfig } from '../config.js'; import { getGlobalVariableBuilder } from '../global_variable_builder/index.js'; -import { getVerificationKeys } from '../mocks/verification_keys.js'; -import { EmptyRollupProver } from '../prover/empty.js'; import { getL1Publisher } from '../publisher/index.js'; import { Sequencer, SequencerConfig } from '../sequencer/index.js'; import { PublicProcessorFactory } from '../sequencer/public_processor.js'; -import { NativeACVMSimulator } from '../simulator/acvm_native.js'; -import { WASMSimulator } from '../simulator/acvm_wasm.js'; -import { RealRollupCircuitSimulator } from '../simulator/rollup.js'; -import { SimulationProvider } from '../simulator/simulation_provider.js'; - -const logger = createDebugLogger('aztec:sequencer-client'); - -/** - * Factory function to create a simulation provider. Will attempt to use native binary simulation falling back to WASM if unavailable. - * @param config - The provided sequencer client configuration - * @returns The constructed simulation provider - */ -async function getSimulationProvider(config: SequencerClientConfig): Promise { - if (config.acvmBinaryPath && config.acvmWorkingDirectory) { - try { - await fs.access(config.acvmBinaryPath, fs.constants.R_OK); - await fs.mkdir(config.acvmWorkingDirectory, { recursive: true }); - logger(`Using native ACVM at ${config.acvmBinaryPath}`); - return new NativeACVMSimulator(config.acvmWorkingDirectory, config.acvmBinaryPath); - } catch { - logger(`Failed to access ACVM at ${config.acvmBinaryPath}, falling back to WASM`); - } - } - logger('Using WASM ACVM simulation'); - return new WASMSimulator(); -} /** * Encapsulates the full sequencer and publisher. @@ -55,6 +25,8 @@ export class SequencerClient { * @param contractDataSource - Provides access to contract bytecode for public executions. * @param l2BlockSource - Provides information about the previously published blocks. * @param l1ToL2MessageSource - Provides access to L1 to L2 messages. + * @param prover - An instance of a block prover + * @param simulationProvider - An instance of a simulation provider * @returns A new running instance. */ public static async new( @@ -64,20 +36,13 @@ export class SequencerClient { contractDataSource: ContractDataSource, l2BlockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, + prover: BlockProver, + simulationProvider: SimulationProvider, ) { const publisher = getL1Publisher(config); const globalsBuilder = getGlobalVariableBuilder(config); const merkleTreeDb = worldStateSynchronizer.getLatest(); - const simulationProvider = await getSimulationProvider(config); - - const blockBuilder = new SoloBlockBuilder( - merkleTreeDb, - getVerificationKeys(), - new RealRollupCircuitSimulator(simulationProvider), - new EmptyRollupProver(), - ); - const publicProcessorFactory = new PublicProcessorFactory( merkleTreeDb, contractDataSource, @@ -90,7 +55,7 @@ export class SequencerClient { globalsBuilder, p2pClient, worldStateSynchronizer, - blockBuilder, + prover, l2BlockSource, l1ToL2MessageSource, publicProcessorFactory, diff --git a/yarn-project/sequencer-client/src/index.ts b/yarn-project/sequencer-client/src/index.ts index 7d4538bf476..ca2c6f3e5a2 100644 --- a/yarn-project/sequencer-client/src/index.ts +++ b/yarn-project/sequencer-client/src/index.ts @@ -1,17 +1,8 @@ export * from './client/index.js'; export * from './config.js'; -export * from './mocks/verification_keys.js'; export * from './publisher/index.js'; export * from './sequencer/index.js'; // Used by the node to simulate public parts of transactions. Should these be moved to a shared library? export * from './global_variable_builder/index.js'; export * from './sequencer/public_processor.js'; - -// Used by publisher test in e2e -export { SoloBlockBuilder } from './block_builder/solo_block_builder.js'; -export { EmptyRollupProver } from './prover/empty.js'; -export { makeEmptyProcessedTx, makeProcessedTx, partitionReverts } from './sequencer/processed_tx.js'; -export { WASMSimulator } from './simulator/acvm_wasm.js'; -export { RealRollupCircuitSimulator } from './simulator/rollup.js'; -export { SimulationProvider } from './simulator/simulation_provider.js'; 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 8d143ed4f0a..0ecd9e56cae 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -38,6 +38,8 @@ import { SideEffect, SideEffectLinkedToNoteHash, VK_TREE_HEIGHT, + VerificationKey, + makeEmptyProof, } from '@aztec/circuits.js'; import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; @@ -55,8 +57,6 @@ import { MerkleTreeOperations } from '@aztec/world-state'; import { env } from 'process'; -import { getVerificationKeys } from '../mocks/verification_keys.js'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { HintsBuilder } from './hints_builder.js'; import { lastSideEffectCounter } from './utils.js'; @@ -82,7 +82,6 @@ export abstract class AbstractPhaseManager { protected db: MerkleTreeOperations, protected publicExecutor: PublicExecutor, protected publicKernel: PublicKernelCircuitSimulator, - protected publicProver: PublicProver, protected globalVariables: GlobalVariables, protected historicalHeader: Header, public phase: PublicKernelPhase, @@ -279,8 +278,7 @@ export abstract class AbstractPhaseManager { callData?: PublicCallData, ): Promise<[PublicKernelCircuitPublicInputs, Proof]> { const output = await this.getKernelCircuitOutput(previousOutput, previousProof, callData); - const proof = await this.publicProver.getPublicKernelCircuitProof(output); - return [output, proof]; + return [output, makeEmptyProof()]; } protected async getKernelCircuitOutput( @@ -331,7 +329,8 @@ export abstract class AbstractPhaseManager { previousOutput: PublicKernelCircuitPublicInputs, previousProof: Proof, ): PublicKernelData { - const vk = getVerificationKeys().publicKernelCircuit; + // TODO(@PhilWindle) Fix once we move this to prover-client + const vk = VerificationKey.makeFake(); const vkIndex = 0; const vkSiblingPath = MembershipWitness.random(VK_TREE_HEIGHT).siblingPath; return new PublicKernelData(previousOutput, previousProof, vk, vkIndex, vkSiblingPath); @@ -434,8 +433,7 @@ export abstract class AbstractPhaseManager { ); const publicCallStack = padArrayEnd(publicCallRequests, CallRequest.empty(), MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL); const portalContractAddress = result.execution.callContext.portalContractAddress.toField(); - const proof = await this.publicProver.getPublicCircuitProof(callStackItem.publicInputs); - return new PublicCallData(callStackItem, publicCallStack, proof, portalContractAddress, bytecodeHash); + return new PublicCallData(callStackItem, publicCallStack, makeEmptyProof(), portalContractAddress, bytecodeHash); } } diff --git a/yarn-project/sequencer-client/src/sequencer/app_logic_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/app_logic_phase_manager.ts index 6c0ab1d6f56..9ba3cf97196 100644 --- a/yarn-project/sequencer-client/src/sequencer/app_logic_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/app_logic_phase_manager.ts @@ -3,7 +3,6 @@ import { GlobalVariables, Header, Proof, PublicKernelCircuitPublicInputs } from import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; @@ -16,14 +15,13 @@ export class AppLogicPhaseManager extends AbstractPhaseManager { protected db: MerkleTreeOperations, protected publicExecutor: PublicExecutor, protected publicKernel: PublicKernelCircuitSimulator, - protected publicProver: PublicProver, protected globalVariables: GlobalVariables, protected historicalHeader: Header, protected publicContractsDB: ContractsDataSourcePublicDB, protected publicStateDB: PublicStateDB, public phase: PublicKernelPhase = PublicKernelPhase.APP_LOGIC, ) { - super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase); + super(db, publicExecutor, publicKernel, globalVariables, historicalHeader, phase); } override async handle( diff --git a/yarn-project/sequencer-client/src/sequencer/phase_manager_factory.ts b/yarn-project/sequencer-client/src/sequencer/phase_manager_factory.ts index 129fdc88129..9c34ee17e1d 100644 --- a/yarn-project/sequencer-client/src/sequencer/phase_manager_factory.ts +++ b/yarn-project/sequencer-client/src/sequencer/phase_manager_factory.ts @@ -3,7 +3,6 @@ import { GlobalVariables, Header, PublicKernelCircuitPublicInputs } from '@aztec import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; @@ -30,7 +29,6 @@ export class PhaseManagerFactory { db: MerkleTreeOperations, publicExecutor: PublicExecutor, publicKernel: PublicKernelCircuitSimulator, - publicProver: PublicProver, globalVariables: GlobalVariables, historicalHeader: Header, publicContractsDB: ContractsDataSourcePublicDB, @@ -41,7 +39,6 @@ export class PhaseManagerFactory { db, publicExecutor, publicKernel, - publicProver, globalVariables, historicalHeader, publicContractsDB, @@ -52,7 +49,6 @@ export class PhaseManagerFactory { db, publicExecutor, publicKernel, - publicProver, globalVariables, historicalHeader, publicContractsDB, @@ -63,7 +59,6 @@ export class PhaseManagerFactory { db, publicExecutor, publicKernel, - publicProver, globalVariables, historicalHeader, publicContractsDB, @@ -80,7 +75,6 @@ export class PhaseManagerFactory { db: MerkleTreeOperations, publicExecutor: PublicExecutor, publicKernel: PublicKernelCircuitSimulator, - publicProver: PublicProver, globalVariables: GlobalVariables, historicalHeader: Header, publicContractsDB: ContractsDataSourcePublicDB, @@ -96,7 +90,6 @@ export class PhaseManagerFactory { db, publicExecutor, publicKernel, - publicProver, globalVariables, historicalHeader, publicContractsDB, @@ -110,7 +103,6 @@ export class PhaseManagerFactory { db, publicExecutor, publicKernel, - publicProver, globalVariables, historicalHeader, publicContractsDB, @@ -121,7 +113,6 @@ export class PhaseManagerFactory { db, publicExecutor, publicKernel, - publicProver, globalVariables, historicalHeader, publicContractsDB, 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 126237a3f72..802a7d98ff0 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -1,12 +1,14 @@ import { FunctionCall, FunctionL2Logs, + ProcessedTx, PublicDataWrite, SiblingPath, SimulationError, Tx, TxL2Logs, mockTx, + toTxEffect, } from '@aztec/circuit-types'; import { ARGS_LENGTH, @@ -42,24 +44,20 @@ import { } from '@aztec/circuits.js/testing'; import { makeTuple } from '@aztec/foundation/array'; import { arrayNonEmptyLength, padArrayEnd, times } from '@aztec/foundation/collection'; -import { PublicExecution, PublicExecutionResult, PublicExecutor } from '@aztec/simulator'; +import { PublicExecution, PublicExecutionResult, PublicExecutor, WASMSimulator } from '@aztec/simulator'; import { MerkleTreeOperations, TreeInfo } from '@aztec/world-state'; import { jest } from '@jest/globals'; import { MockProxy, mock } from 'jest-mock-extended'; -import { PublicProver } from '../prover/index.js'; -import { WASMSimulator } from '../simulator/acvm_wasm.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB, WorldStatePublicDB } from '../simulator/public_executor.js'; import { RealPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'; -import { ProcessedTx, toTxEffect } from './processed_tx.js'; import { PublicProcessor } from './public_processor.js'; describe('public_processor', () => { let db: MockProxy; let publicExecutor: MockProxy; - let publicProver: MockProxy; let publicContractsDB: MockProxy; let publicWorldStateDB: MockProxy; @@ -71,15 +69,12 @@ describe('public_processor', () => { beforeEach(() => { db = mock(); publicExecutor = mock(); - publicProver = mock(); publicContractsDB = mock(); publicWorldStateDB = mock(); proof = makeEmptyProof(); root = Buffer.alloc(32, 5); - publicProver.getPublicCircuitProof.mockResolvedValue(proof); - publicProver.getPublicKernelCircuitProof.mockResolvedValue(proof); db.getTreeInfo.mockResolvedValue({ root } as TreeInfo); }); @@ -92,7 +87,6 @@ describe('public_processor', () => { db, publicExecutor, publicKernel, - publicProver, GlobalVariables.empty(), Header.empty(), publicContractsDB, @@ -180,7 +174,6 @@ describe('public_processor', () => { db, publicExecutor, publicKernel, - publicProver, GlobalVariables.empty(), Header.empty(), publicContractsDB, diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 1c620bd2787..98a1b4a4a71 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -1,28 +1,27 @@ -import { L1ToL2MessageSource, SimulationError, Tx } from '@aztec/circuit-types'; +import { + FailedTx, + L1ToL2MessageSource, + ProcessedTx, + SimulationError, + Tx, + getPreviousOutputAndProof, + makeEmptyProcessedTx, + makeProcessedTx, + validateProcessedTx, +} from '@aztec/circuit-types'; import { TxSequencerProcessingStats } from '@aztec/circuit-types/stats'; import { GlobalVariables, Header } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; -import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; +import { PublicExecutor, PublicStateDB, SimulationProvider } from '@aztec/simulator'; import { ContractDataSource } from '@aztec/types/contracts'; import { MerkleTreeOperations } from '@aztec/world-state'; -import { EmptyPublicProver } from '../prover/empty.js'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB, WorldStateDB, WorldStatePublicDB } from '../simulator/public_executor.js'; import { RealPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'; -import { SimulationProvider } from '../simulator/simulation_provider.js'; import { AbstractPhaseManager } from './abstract_phase_manager.js'; import { PhaseManagerFactory } from './phase_manager_factory.js'; -import { - FailedTx, - ProcessedTx, - getPreviousOutputAndProof, - makeEmptyProcessedTx, - makeProcessedTx, - validateProcessedTx, -} from './processed_tx.js'; /** * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source. @@ -56,7 +55,6 @@ export class PublicProcessorFactory { this.merkleTree, publicExecutor, new RealPublicKernelCircuitSimulator(this.simulator), - new EmptyPublicProver(), globalVariables, historicalHeader, publicContractsDB, @@ -74,7 +72,6 @@ export class PublicProcessor { protected db: MerkleTreeOperations, protected publicExecutor: PublicExecutor, protected publicKernel: PublicKernelCircuitSimulator, - protected publicProver: PublicProver, protected globalVariables: GlobalVariables, protected historicalHeader: Header, protected publicContractsDB: ContractsDataSourcePublicDB, @@ -100,7 +97,6 @@ export class PublicProcessor { this.db, this.publicExecutor, this.publicKernel, - this.publicProver, this.globalVariables, this.historicalHeader, this.publicContractsDB, @@ -122,7 +118,6 @@ export class PublicProcessor { this.db, this.publicExecutor, this.publicKernel, - this.publicProver, this.globalVariables, this.historicalHeader, this.publicContractsDB, diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 61ccb97a346..10d5878e81f 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -1,4 +1,16 @@ -import { L1ToL2MessageSource, L2Block, L2BlockSource, MerkleTreeId, Tx, TxHash, mockTx } from '@aztec/circuit-types'; +import { + L1ToL2MessageSource, + L2Block, + L2BlockSource, + MerkleTreeId, + PROVING_STATUS, + ProverClient, + ProvingSuccess, + ProvingTicket, + makeEmptyProcessedTx, + makeProcessedTx, + mockTx, +} from '@aztec/circuit-types'; import { AztecAddress, EthAddress, @@ -8,16 +20,13 @@ import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, makeEmptyProof, } from '@aztec/circuits.js'; -import { times } from '@aztec/foundation/collection'; import { P2P, P2PClientState } from '@aztec/p2p'; import { MerkleTreeOperations, WorldStateRunningState, WorldStateSynchronizer } from '@aztec/world-state'; import { MockProxy, mock, mockFn } from 'jest-mock-extended'; -import { BlockBuilder } from '../block_builder/index.js'; import { GlobalVariableBuilder } from '../global_variable_builder/global_builder.js'; import { L1Publisher } from '../index.js'; -import { makeEmptyProcessedTx, makeProcessedTx } from './processed_tx.js'; import { PublicProcessor, PublicProcessorFactory } from './public_processor.js'; import { Sequencer } from './sequencer.js'; @@ -26,7 +35,7 @@ describe('sequencer', () => { let globalVariableBuilder: MockProxy; let p2p: MockProxy; let worldState: MockProxy; - let blockBuilder: MockProxy; + let proverClient: MockProxy; let merkleTreeOps: MockProxy; let publicProcessor: MockProxy; let l2BlockSource: MockProxy; @@ -48,7 +57,7 @@ describe('sequencer', () => { publisher = mock(); globalVariableBuilder = mock(); merkleTreeOps = mock(); - blockBuilder = mock(); + proverClient = mock(); p2p = mock({ getStatus: () => Promise.resolve({ state: P2PClientState.IDLE, syncedToL2Block: lastBlockNumber }), @@ -82,7 +91,7 @@ describe('sequencer', () => { globalVariableBuilder, p2p, worldState, - blockBuilder, + proverClient, l2BlockSource, l1ToL2MessageSource, publicProcessorFactory, @@ -96,9 +105,17 @@ describe('sequencer', () => { tx.data.needsTeardown = false; const block = L2Block.random(lastBlockNumber + 1); const proof = makeEmptyProof(); + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + proof, + block, + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; p2p.getTxs.mockResolvedValueOnce([tx]); - blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); + proverClient.startNewBlock.mockResolvedValueOnce(ticket); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), @@ -107,13 +124,13 @@ describe('sequencer', () => { await sequencer.initialSync(); await sequencer.work(); - const expectedTxHashes = [...Tx.getHashes([tx]), ...times(1, () => TxHash.ZERO)]; - - expect(blockBuilder.buildL2Block).toHaveBeenCalledWith( + expect(proverClient.startNewBlock).toHaveBeenCalledWith( + 1, new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), - expectedTxHashes.map(hash => expect.objectContaining({ hash })), Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), + publicProcessor.makeEmptyProcessedTx(), ); + expect(proverClient.addNewTx).toHaveBeenCalledWith(expect.objectContaining({ hash: tx.getTxHash() })); expect(publisher.processL2Block).toHaveBeenCalledWith(block); }); @@ -127,9 +144,17 @@ describe('sequencer', () => { const doubleSpendTx = txs[1]; const block = L2Block.random(lastBlockNumber + 1); const proof = makeEmptyProof(); + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + proof, + block, + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; p2p.getTxs.mockResolvedValueOnce(txs); - blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); + proverClient.startNewBlock.mockResolvedValueOnce(ticket); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), @@ -146,13 +171,14 @@ describe('sequencer', () => { await sequencer.initialSync(); await sequencer.work(); - const expectedTxHashes = Tx.getHashes([txs[0], txs[2]]); - - expect(blockBuilder.buildL2Block).toHaveBeenCalledWith( + expect(proverClient.startNewBlock).toHaveBeenCalledWith( + 2, new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), - expectedTxHashes.map(hash => expect.objectContaining({ hash })), Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), + publicProcessor.makeEmptyProcessedTx(), ); + expect(proverClient.addNewTx).toHaveBeenCalledWith(expect.objectContaining({ hash: txs[0].getTxHash() })); + expect(proverClient.addNewTx).toHaveBeenCalledWith(expect.objectContaining({ hash: txs[2].getTxHash() })); expect(publisher.processL2Block).toHaveBeenCalledWith(block); expect(p2p.deleteTxs).toHaveBeenCalledWith([doubleSpendTx.getTxHash()]); }); @@ -167,9 +193,17 @@ describe('sequencer', () => { const invalidChainTx = txs[1]; const block = L2Block.random(lastBlockNumber + 1); const proof = makeEmptyProof(); + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + proof, + block, + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; p2p.getTxs.mockResolvedValueOnce(txs); - blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); + proverClient.startNewBlock.mockResolvedValueOnce(ticket); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), @@ -181,13 +215,14 @@ describe('sequencer', () => { await sequencer.initialSync(); await sequencer.work(); - const expectedTxHashes = Tx.getHashes([txs[0], txs[2]]); - - expect(blockBuilder.buildL2Block).toHaveBeenCalledWith( + expect(proverClient.startNewBlock).toHaveBeenCalledWith( + 2, new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), - expectedTxHashes.map(hash => expect.objectContaining({ hash })), Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), + publicProcessor.makeEmptyProcessedTx(), ); + expect(proverClient.addNewTx).toHaveBeenCalledWith(expect.objectContaining({ hash: txs[0].getTxHash() })); + expect(proverClient.addNewTx).toHaveBeenCalledWith(expect.objectContaining({ hash: txs[2].getTxHash() })); expect(publisher.processL2Block).toHaveBeenCalledWith(block); expect(p2p.deleteTxs).toHaveBeenCalledWith([invalidChainTx.getTxHash()]); }); @@ -197,9 +232,17 @@ describe('sequencer', () => { tx.data.constants.txContext.chainId = chainId; const block = L2Block.random(lastBlockNumber + 1); const proof = makeEmptyProof(); + const result: ProvingSuccess = { + status: PROVING_STATUS.SUCCESS, + proof, + block, + }; + const ticket: ProvingTicket = { + provingPromise: Promise.resolve(result), + }; p2p.getTxs.mockResolvedValueOnce([tx]); - blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); + proverClient.startNewBlock.mockResolvedValueOnce(ticket); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 84ce6bf3dfe..f4c3481a272 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -1,7 +1,7 @@ -import { L1ToL2MessageSource, L2Block, L2BlockSource, MerkleTreeId, Tx } from '@aztec/circuit-types'; +import { L1ToL2MessageSource, L2Block, L2BlockSource, MerkleTreeId, ProcessedTx, Tx } from '@aztec/circuit-types'; +import { BlockProver, PROVING_STATUS } from '@aztec/circuit-types/interfaces'; import { L2BlockBuiltStats } from '@aztec/circuit-types/stats'; import { AztecAddress, EthAddress, GlobalVariables } from '@aztec/circuits.js'; -import { times } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; @@ -9,13 +9,10 @@ import { Timer, elapsed } from '@aztec/foundation/timer'; import { P2P } from '@aztec/p2p'; import { WorldStateStatus, WorldStateSynchronizer } from '@aztec/world-state'; -import { BlockBuilder } from '../block_builder/index.js'; import { GlobalVariableBuilder } from '../global_variable_builder/global_builder.js'; import { L1Publisher } from '../publisher/l1-publisher.js'; import { WorldStatePublicDB } from '../simulator/public_executor.js'; -import { ceilPowerOfTwo } from '../utils.js'; import { SequencerConfig } from './config.js'; -import { ProcessedTx } from './processed_tx.js'; import { PublicProcessorFactory } from './public_processor.js'; import { TxValidator } from './tx_validator.js'; @@ -44,7 +41,7 @@ export class Sequencer { private globalsBuilder: GlobalVariableBuilder, private p2pClient: P2P, private worldState: WorldStateSynchronizer, - private blockBuilder: BlockBuilder, + private prover: BlockProver, private l2BlockSource: L2BlockSource, private l1ToL2MessageSource: L1ToL2MessageSource, private publicProcessorFactory: PublicProcessorFactory, @@ -305,15 +302,17 @@ export class Sequencer { emptyTx: ProcessedTx, globalVariables: GlobalVariables, ) { - // Pad the txs array with empty txs to be a power of two, at least 2 - const txsTargetSize = Math.max(ceilPowerOfTwo(txs.length), 2); - const emptyTxCount = txsTargetSize - txs.length; + const blockTicket = await this.prover.startNewBlock(txs.length, globalVariables, l1ToL2Messages, emptyTx); - const allTxs = [...txs, ...times(emptyTxCount, () => emptyTx)]; - this.log(`Building block ${globalVariables.blockNumber.toBigInt()}`); + for (const tx of txs) { + await this.prover.addNewTx(tx); + } - const [block] = await this.blockBuilder.buildL2Block(globalVariables, allTxs, l1ToL2Messages); - return block; + const result = await blockTicket.provingPromise; + if (result.status === PROVING_STATUS.FAILURE) { + throw new Error(`Block proving failed, reason: ${result.reason}`); + } + return result.block; } get coinbase(): EthAddress { diff --git a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.test.ts b/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.test.ts index 853bd0e8d1a..9b198177c62 100644 --- a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.test.ts @@ -5,8 +5,6 @@ import { Header, MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - Proof, - makeEmptyProof, } from '@aztec/circuits.js'; import { makeTuple } from '@aztec/foundation/array'; import { PublicExecutor } from '@aztec/simulator'; @@ -15,7 +13,6 @@ import { MerkleTreeOperations, TreeInfo } from '@aztec/world-state'; import { it } from '@jest/globals'; import { MockProxy, mock } from 'jest-mock-extended'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB, WorldStatePublicDB } from '../simulator/public_executor.js'; import { SetupPhaseManager } from './setup_phase_manager.js'; @@ -29,12 +26,10 @@ class TestSetupPhaseManager extends SetupPhaseManager { describe('setup_phase_manager', () => { let db: MockProxy; let publicExecutor: MockProxy; - let publicProver: MockProxy; let publicContractsDB: MockProxy; let publicWorldStateDB: MockProxy; let publicKernel: MockProxy; - let proof: Proof; let root: Buffer; let phaseManager: TestSetupPhaseManager; @@ -42,22 +37,16 @@ describe('setup_phase_manager', () => { beforeEach(() => { db = mock(); publicExecutor = mock(); - publicProver = mock(); publicContractsDB = mock(); publicWorldStateDB = mock(); - proof = makeEmptyProof(); root = Buffer.alloc(32, 5); - - publicProver.getPublicCircuitProof.mockResolvedValue(proof); - publicProver.getPublicKernelCircuitProof.mockResolvedValue(proof); db.getTreeInfo.mockResolvedValue({ root } as TreeInfo); publicKernel = mock(); phaseManager = new TestSetupPhaseManager( db, publicExecutor, publicKernel, - publicProver, GlobalVariables.empty(), Header.empty(), publicContractsDB, diff --git a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts index f30c50ee3e4..76da4e232a6 100644 --- a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts @@ -3,7 +3,6 @@ import { GlobalVariables, Header, Proof, PublicKernelCircuitPublicInputs } from import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; @@ -16,14 +15,13 @@ export class SetupPhaseManager extends AbstractPhaseManager { protected db: MerkleTreeOperations, protected publicExecutor: PublicExecutor, protected publicKernel: PublicKernelCircuitSimulator, - protected publicProver: PublicProver, protected globalVariables: GlobalVariables, protected historicalHeader: Header, protected publicContractsDB: ContractsDataSourcePublicDB, protected publicStateDB: PublicStateDB, public phase: PublicKernelPhase = PublicKernelPhase.SETUP, ) { - super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase); + super(db, publicExecutor, publicKernel, globalVariables, historicalHeader, phase); } override async handle( diff --git a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts index 804623c13c1..0fe236452d9 100644 --- a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts @@ -3,7 +3,6 @@ import { GlobalVariables, Header, Proof, PublicKernelCircuitPublicInputs } from import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; @@ -13,14 +12,13 @@ export class TailPhaseManager extends AbstractPhaseManager { protected db: MerkleTreeOperations, protected publicExecutor: PublicExecutor, protected publicKernel: PublicKernelCircuitSimulator, - protected publicProver: PublicProver, protected globalVariables: GlobalVariables, protected historicalHeader: Header, protected publicContractsDB: ContractsDataSourcePublicDB, protected publicStateDB: PublicStateDB, public readonly phase: PublicKernelPhase = PublicKernelPhase.TAIL, ) { - super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase); + super(db, publicExecutor, publicKernel, globalVariables, historicalHeader, phase); } async handle(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs, previousPublicKernelProof: Proof) { diff --git a/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts index f263806caf5..ddaaa7c8943 100644 --- a/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts @@ -3,7 +3,6 @@ import { GlobalVariables, Header, Proof, PublicKernelCircuitPublicInputs } from import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; -import { PublicProver } from '../prover/index.js'; import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; @@ -16,14 +15,13 @@ export class TeardownPhaseManager extends AbstractPhaseManager { protected db: MerkleTreeOperations, protected publicExecutor: PublicExecutor, protected publicKernel: PublicKernelCircuitSimulator, - protected publicProver: PublicProver, protected globalVariables: GlobalVariables, protected historicalHeader: Header, protected publicContractsDB: ContractsDataSourcePublicDB, protected publicStateDB: PublicStateDB, public phase: PublicKernelPhase = PublicKernelPhase.TEARDOWN, ) { - super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase); + super(db, publicExecutor, publicKernel, globalVariables, historicalHeader, phase); } override async handle( diff --git a/yarn-project/sequencer-client/src/sequencer/tx_validator.ts b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts index 271b9a2928c..621ec88abde 100644 --- a/yarn-project/sequencer-client/src/sequencer/tx_validator.ts +++ b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts @@ -1,11 +1,10 @@ -import { Tx } from '@aztec/circuit-types'; +import { ProcessedTx, Tx } from '@aztec/circuit-types'; import { AztecAddress, EthAddress, Fr, GlobalVariables } from '@aztec/circuits.js'; import { pedersenHash } from '@aztec/foundation/crypto'; import { Logger, createDebugLogger } from '@aztec/foundation/log'; import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js'; -import { ProcessedTx } from './processed_tx.js'; /** A source of what nullifiers have been committed to the state trees */ export interface NullifierSource { diff --git a/yarn-project/sequencer-client/src/simulator/index.ts b/yarn-project/sequencer-client/src/simulator/index.ts index 9f25ce30388..ba9106b6b1a 100644 --- a/yarn-project/sequencer-client/src/simulator/index.ts +++ b/yarn-project/sequencer-client/src/simulator/index.ts @@ -1,53 +1,9 @@ import { - BaseOrMergeRollupPublicInputs, - BaseParityInputs, - BaseRollupInputs, - MergeRollupInputs, - ParityPublicInputs, PublicKernelCircuitPrivateInputs, PublicKernelCircuitPublicInputs, PublicKernelTailCircuitPrivateInputs, - RootParityInputs, - RootRollupInputs, - RootRollupPublicInputs, } from '@aztec/circuits.js'; -/** - * Circuit simulator for the rollup circuits. - */ -export interface RollupSimulator { - /** - * Simulates the base parity circuit from its inputs. - * @param inputs - Inputs to the circuit. - * @returns The public inputs of the parity circuit. - */ - baseParityCircuit(inputs: BaseParityInputs): Promise; - /** - * Simulates the root parity circuit from its inputs. - * @param inputs - Inputs to the circuit. - * @returns The public inputs of the parity circuit. - */ - rootParityCircuit(inputs: RootParityInputs): Promise; - /** - * Simulates the base rollup circuit from its inputs. - * @param input - Inputs to the circuit. - * @returns The public inputs as outputs of the simulation. - */ - baseRollupCircuit(input: BaseRollupInputs): Promise; - /** - * Simulates the merge rollup circuit from its inputs. - * @param input - Inputs to the circuit. - * @returns The public inputs as outputs of the simulation. - */ - mergeRollupCircuit(input: MergeRollupInputs): Promise; - /** - * Simulates the root rollup circuit from its inputs. - * @param input - Inputs to the circuit. - * @returns The public inputs as outputs of the simulation. - */ - rootRollupCircuit(input: RootRollupInputs): Promise; -} - /** * Circuit simulator for the public kernel circuits. */ @@ -77,4 +33,3 @@ export interface PublicKernelCircuitSimulator { */ publicKernelCircuitTail(inputs: PublicKernelTailCircuitPrivateInputs): Promise; } -export * from './acvm_wasm.js'; diff --git a/yarn-project/sequencer-client/src/simulator/public_kernel.ts b/yarn-project/sequencer-client/src/simulator/public_kernel.ts index 0d6a3efa015..c60e74b63ae 100644 --- a/yarn-project/sequencer-client/src/simulator/public_kernel.ts +++ b/yarn-project/sequencer-client/src/simulator/public_kernel.ts @@ -20,9 +20,9 @@ import { convertPublicTeardownRollupInputsToWitnessMap, convertPublicTeardownRollupOutputFromWitnessMap, } from '@aztec/noir-protocol-circuits-types'; +import { SimulationProvider, WASMSimulator } from '@aztec/simulator'; -import { PublicKernelCircuitSimulator, WASMSimulator } from './index.js'; -import { SimulationProvider } from './simulation_provider.js'; +import { PublicKernelCircuitSimulator } from './index.js'; /** * Implements the PublicKernelCircuitSimulator. diff --git a/yarn-project/simulator/package.json b/yarn-project/simulator/package.json index 18e69ceb7d9..3999470cf4d 100644 --- a/yarn-project/simulator/package.json +++ b/yarn-project/simulator/package.json @@ -35,6 +35,7 @@ "@aztec/foundation": "workspace:^", "@aztec/types": "workspace:^", "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js", + "@noir-lang/types": "portal:../../noir/packages/types", "levelup": "^5.1.1", "memdown": "^6.1.1", "tslib": "^2.4.0" diff --git a/yarn-project/simulator/src/index.ts b/yarn-project/simulator/src/index.ts index 83725c7d2be..e55ef8e402e 100644 --- a/yarn-project/simulator/src/index.ts +++ b/yarn-project/simulator/src/index.ts @@ -2,3 +2,4 @@ export * from './acvm/index.js'; export * from './client/index.js'; export * from './common/index.js'; export * from './public/index.js'; +export * from './simulator/index.js'; diff --git a/yarn-project/sequencer-client/src/simulator/acvm_native.ts b/yarn-project/simulator/src/simulator/acvm_native.ts similarity index 100% rename from yarn-project/sequencer-client/src/simulator/acvm_native.ts rename to yarn-project/simulator/src/simulator/acvm_native.ts diff --git a/yarn-project/sequencer-client/src/simulator/acvm_wasm.ts b/yarn-project/simulator/src/simulator/acvm_wasm.ts similarity index 100% rename from yarn-project/sequencer-client/src/simulator/acvm_wasm.ts rename to yarn-project/simulator/src/simulator/acvm_wasm.ts diff --git a/yarn-project/simulator/src/simulator/index.ts b/yarn-project/simulator/src/simulator/index.ts new file mode 100644 index 00000000000..936e33be0fa --- /dev/null +++ b/yarn-project/simulator/src/simulator/index.ts @@ -0,0 +1,3 @@ +export * from './acvm_native.js'; +export * from './acvm_wasm.js'; +export * from './simulation_provider.js'; diff --git a/yarn-project/sequencer-client/src/simulator/simulation_provider.ts b/yarn-project/simulator/src/simulator/simulation_provider.ts similarity index 100% rename from yarn-project/sequencer-client/src/simulator/simulation_provider.ts rename to yarn-project/simulator/src/simulator/simulation_provider.ts diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 83d063e6450..a7437ba5451 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -150,7 +150,9 @@ __metadata: "@aztec/l1-artifacts": "workspace:^" "@aztec/merkle-tree": "workspace:^" "@aztec/p2p": "workspace:^" + "@aztec/prover-client": "workspace:^" "@aztec/sequencer-client": "workspace:^" + "@aztec/simulator": "workspace:^" "@aztec/types": "workspace:^" "@aztec/world-state": "workspace:^" "@jest/globals": ^29.5.0 @@ -384,8 +386,10 @@ __metadata: "@aztec/noir-contracts.js": "workspace:^" "@aztec/p2p": "workspace:^" "@aztec/protocol-contracts": "workspace:^" + "@aztec/prover-client": "workspace:^" "@aztec/pxe": "workspace:^" "@aztec/sequencer-client": "workspace:^" + "@aztec/simulator": "workspace:^" "@aztec/types": "workspace:^" "@aztec/world-state": "workspace:^" "@jest/globals": ^29.5.0 @@ -403,6 +407,7 @@ __metadata: crypto-browserify: ^3.12.0 glob: ^10.3.10 jest: ^29.5.0 + jest-mock-extended: ^3.0.5 koa: ^2.14.2 koa-static: ^5.0.0 levelup: ^5.1.1 @@ -746,15 +751,24 @@ __metadata: languageName: unknown linkType: soft -"@aztec/prover-client@workspace:prover-client": +"@aztec/prover-client@workspace:^, @aztec/prover-client@workspace:prover-client": version: 0.0.0-use.local resolution: "@aztec/prover-client@workspace:prover-client" dependencies: + "@aztec/circuit-types": "workspace:^" + "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" + "@aztec/noir-protocol-circuits-types": "workspace:^" + "@aztec/simulator": "workspace:^" + "@aztec/world-state": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 + "@types/memdown": ^3.0.0 "@types/node": ^18.7.23 jest: ^29.5.0 + jest-mock-extended: ^3.0.3 + lodash.chunk: ^4.2.0 ts-jest: ^29.1.0 ts-node: ^10.9.1 tslib: ^2.4.0 @@ -879,6 +893,7 @@ __metadata: "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js" + "@noir-lang/types": "portal:../../noir/packages/types" "@types/jest": ^29.5.0 "@types/levelup": ^5.1.3 "@types/lodash.merge": ^4.6.9 From 9bc42497d3d84c1df3eb6754424ce4122bb45883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Fri, 22 Mar 2024 14:13:07 +0100 Subject: [PATCH 25/36] refactor: messaging naming fixes (#5383) Some naming fixes we discussed in our team chat and which Lasse [disliked](https://github.com/AztecProtocol/aztec-packages/pull/5206#discussion_r1528245150) in my purge PR a few days ago. \+ nuked some stale stuff from contracts. --- .../references/portals/data_structures.md | 12 -- .../developers/debugging/sandbox-errors.md | 4 +- l1-contracts/GUIDE_LINES.md | 17 ++- l1-contracts/slither_output.md | 50 ++------ .../core/interfaces/messagebridge/IInbox.sol | 10 +- .../src/core/libraries/DataStructures.sol | 16 --- l1-contracts/src/core/libraries/Errors.sol | 4 +- .../src/core/libraries/MessageBox.sol | 113 ------------------ l1-contracts/src/core/messagebridge/Inbox.sol | 6 +- l1-contracts/test/Inbox.t.sol | 2 +- l1-contracts/test/Registry.t.sol | 1 - l1-contracts/test/portals/TokenPortal.t.sol | 6 +- l1-contracts/test/portals/UniswapPortal.sol | 4 +- l1-contracts/test/portals/UniswapPortal.t.sol | 89 +++++++------- noir-projects/aztec-nr/aztec/src/messaging.nr | 6 +- .../oracle/get_l1_to_l2_membership_witness.nr | 8 +- .../archiver/src/archiver/archiver.test.ts | 26 ++-- .../archiver/src/archiver/archiver.ts | 17 +-- .../archiver/src/archiver/archiver_store.ts | 10 +- .../src/archiver/archiver_store_test_suite.ts | 20 ++-- .../archiver/src/archiver/data_retrieval.ts | 12 +- .../archiver/src/archiver/eth_log_handlers.ts | 24 ++-- .../kv_archiver_store/kv_archiver_store.ts | 8 +- .../l1_to_l2_message_store.ts | 3 +- .../memory_archiver_store.ts | 6 +- .../aztec-node/src/aztec-node/server.ts | 12 +- .../src/interfaces/aztec-node.ts | 9 +- .../circuit-types/src/messaging/inbox_leaf.ts | 2 +- .../src/messaging/l1_to_l2_message.ts | 8 +- .../src/e2e_cross_chain_messaging.test.ts | 16 +-- .../end-to-end/src/e2e_outbox.test.ts | 16 +-- .../e2e_public_cross_chain_messaging.test.ts | 26 ++-- .../e2e_public_to_private_messaging.test.ts | 4 +- .../src/integration_l1_publisher.test.ts | 2 +- .../src/shared/cross_chain_test_harness.ts | 18 +-- .../src/shared/gas_portal_test_harness.ts | 8 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 36 +++--- .../pxe/src/simulator_oracle/index.ts | 15 +-- .../src/simulator/public_executor.ts | 6 +- .../simulator/src/acvm/oracle/oracle.ts | 4 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 2 +- .../simulator/src/client/view_data_oracle.ts | 8 +- yarn-project/simulator/src/public/db.ts | 8 +- .../src/public/public_execution_context.ts | 6 +- 44 files changed, 258 insertions(+), 422 deletions(-) delete mode 100644 l1-contracts/src/core/libraries/MessageBox.sol diff --git a/docs/docs/developers/contracts/references/portals/data_structures.md b/docs/docs/developers/contracts/references/portals/data_structures.md index babbe4211d0..ba97bfd5272 100644 --- a/docs/docs/developers/contracts/references/portals/data_structures.md +++ b/docs/docs/developers/contracts/references/portals/data_structures.md @@ -6,18 +6,6 @@ The `DataStructures` are structs that we are using throughout the message infras **Links**: [Implementation](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/DataStructures.sol). -## `Entry` - -An entry for the messageboxes multi-sets. - -#include_code data_structure_entry l1-contracts/src/core/libraries/DataStructures.sol solidity - -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `count` | `uint32` | The occurrence of the entry in the dataset | -| `version` | `uint32` | The version of the entry | - - ## `L1Actor` An entity on L1, specifying the address and the chainId for the entity. Used when specifying sender/recipient with an entity that is on L1. diff --git a/docs/docs/developers/debugging/sandbox-errors.md b/docs/docs/developers/debugging/sandbox-errors.md index 0dfb7675713..911654026b6 100644 --- a/docs/docs/developers/debugging/sandbox-errors.md +++ b/docs/docs/developers/debugging/sandbox-errors.md @@ -177,9 +177,7 @@ Users may create a proof against a historical state in Aztec. The rollup circuit ## Archiver Errors -- "L1 to L2 Message with key ${entryKey.toString()} not found in the confirmed messages store" - happens when the L1 to L2 message doesn't exist or is "pending", when the user has sent a message on L1 via the Inbox contract but it has yet to be included in an L2 block by the sequencer - user has to wait for sequencer to pick it up and the archiver to sync the respective L2 block. You can get the sequencer to pick it up by doing an arbitrary transaction on L2 (eg send DAI to yourself). This would give the sequencer a transaction to process and as a side effect it would look for any pending messages it should include. - -- "Unable to remove message: L1 to L2 Message with key ${entryKeyBigInt} not found in store" - happens when trying to confirm a non-existent pending message or cancelling such a message. Perhaps the sequencer has already confirmed the message? +- "No L1 to L2 message found for message hash ${messageHash.toString()}" - happens when the L1 to L2 message doesn't exist or is "pending", when the user has sent a message on L1 via the Inbox contract but it has yet to be included in an L2 block by the sequencer - user has to wait for enough blocks to progress and for the archiver to sync the respective L2 block. You can get the sequencer to pick it up by doing 2 arbitrary transaction on L2 (eg. send DAI to yourself 2 times). This would give the sequencer a transaction to process and as a side effect it would consume 2 subtrees of new messages from the Inbox contract. 2 subtrees needs to be consumed and not just 1 because there is a 1 block lag to prevent the subtree from changing when the sequencer is proving. - "Block number mismatch: expected ${l2BlockNum} but got ${block.number}" - The archiver keeps track of the next expected L2 block number. It throws this error if it got a different one when trying to sync with the rollup contract's events on L1. diff --git a/l1-contracts/GUIDE_LINES.md b/l1-contracts/GUIDE_LINES.md index e62096e2bab..4e4ea93a552 100644 --- a/l1-contracts/GUIDE_LINES.md +++ b/l1-contracts/GUIDE_LINES.md @@ -120,13 +120,18 @@ Natspec should be written for all functions (`internal` mainly for clarity). Use ```solidity /** - * @notice Consumes an entry from the Outbox - * @dev Only meaningfully callable by portals, otherwise should never hit an entry - * @dev Emits the `MessageConsumed` event when consuming messages - * @param _message - The L2 to L1 message - * @return entryKey - The key of the entry removed + * @notice Inserts a new message into the Inbox + * @dev Emits `MessageSent` with data for easy access by the sequencer + * @param _recipient - The recipient of the message + * @param _content - The content of the message (application specific) + * @param _secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on L2) + * @return Hash of the sent message. */ - function consume(DataStructures.L2ToL1Msg memory _message) + function sendL2Message( + DataStructures.L2Actor memory _recipient, + bytes32 _content, + bytes32 _secretHash + ) external override(IInbox) returns (bytes32) { ``` ### Solhint configuration diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 9b23244910e..17f01315b45 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -7,7 +7,7 @@ Summary - [timestamp](#timestamp) (1 results) (Low) - [pess-public-vs-external](#pess-public-vs-external) (5 results) (Low) - [assembly](#assembly) (1 results) (Informational) - - [dead-code](#dead-code) (5 results) (Informational) + - [dead-code](#dead-code) (1 results) (Informational) - [solc-version](#solc-version) (1 results) (Informational) - [similar-names](#similar-names) (3 results) (Informational) - [constable-states](#constable-states) (1 results) (Optimization) @@ -123,7 +123,7 @@ Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/ External calls: - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/Inbox.sol#L91) Event emitted after the call(s): - - [LeafInserted(inProgress,index,leaf)](src/core/messagebridge/Inbox.sol#L92) + - [MessageSent(inProgress,index,leaf)](src/core/messagebridge/Inbox.sol#L92) src/core/messagebridge/Inbox.sol#L61-L95 @@ -191,30 +191,6 @@ src/core/libraries/decoders/TxsDecoder.sol#L258-L277 Impact: Informational Confidence: Medium - [ ] ID-18 -[MessageBox.consume(mapping(bytes32 => DataStructures.Entry),bytes32,function(bytes32))](src/core/libraries/MessageBox.sol#L71-L79) is never used and should be removed - -src/core/libraries/MessageBox.sol#L71-L79 - - - - [ ] ID-19 -[MessageBox.contains(mapping(bytes32 => DataStructures.Entry),bytes32)](src/core/libraries/MessageBox.sol#L87-L92) is never used and should be removed - -src/core/libraries/MessageBox.sol#L87-L92 - - - - [ ] ID-20 -[MessageBox.get(mapping(bytes32 => DataStructures.Entry),bytes32,function(bytes32))](src/core/libraries/MessageBox.sol#L104-L112) is never used and should be removed - -src/core/libraries/MessageBox.sol#L104-L112 - - - - [ ] ID-21 -[MessageBox.insert(mapping(bytes32 => DataStructures.Entry),bytes32,uint64,uint32,uint32,function(bytes32,uint64,uint64,uint32,uint32,uint32,uint32))](src/core/libraries/MessageBox.sol#L30-L60) is never used and should be removed - -src/core/libraries/MessageBox.sol#L30-L60 - - - - [ ] ID-22 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed src/core/libraries/Hash.sol#L52-L54 @@ -223,25 +199,25 @@ src/core/libraries/Hash.sol#L52-L54 ## solc-version Impact: Informational Confidence: High - - [ ] ID-23 + - [ ] ID-19 solc-0.8.23 is not recommended for deployment ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-24 + - [ ] ID-20 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) src/core/libraries/ConstantsGen.sol#L130 - - [ ] ID-25 + - [ ] ID-21 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) src/core/libraries/ConstantsGen.sol#L110 - - [ ] ID-26 + - [ ] ID-22 Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L32) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L43) src/core/Rollup.sol#L32 @@ -250,7 +226,7 @@ src/core/Rollup.sol#L32 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-27 + - [ ] ID-23 [Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L41) should be constant src/core/Rollup.sol#L41 @@ -259,37 +235,37 @@ src/core/Rollup.sol#L41 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-28 + - [ ] ID-24 In a function [Outbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/Outbox.sol#L44-L64) variable [Outbox.roots](src/core/messagebridge/Outbox.sol#L29) is read multiple times src/core/messagebridge/Outbox.sol#L44-L64 - - [ ] ID-29 + - [ ] ID-25 In a function [Inbox.consume()](src/core/messagebridge/Inbox.sol#L104-L123) variable [Inbox.toConsume](src/core/messagebridge/Inbox.sol#L34) is read multiple times src/core/messagebridge/Inbox.sol#L104-L123 - - [ ] ID-30 + - [ ] ID-26 In a function [Inbox.consume()](src/core/messagebridge/Inbox.sol#L104-L123) variable [Inbox.inProgress](src/core/messagebridge/Inbox.sol#L36) is read multiple times src/core/messagebridge/Inbox.sol#L104-L123 - - [ ] ID-31 + - [ ] ID-27 In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81) variable [FrontierMerkle.HEIGHT](src/core/messagebridge/frontier_tree/Frontier.sol#L13) is read multiple times src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81 - - [ ] ID-32 + - [ ] ID-28 In a function [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L61-L95) variable [Inbox.inProgress](src/core/messagebridge/Inbox.sol#L36) is read multiple times src/core/messagebridge/Inbox.sol#L61-L95 - - [ ] ID-33 + - [ ] ID-29 In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81) variable [FrontierMerkle.frontier](src/core/messagebridge/frontier_tree/Frontier.sol#L18) is read multiple times src/core/messagebridge/frontier_tree/Frontier.sol#L48-L81 diff --git a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol index b5a261d0ef3..2139bd78483 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol @@ -10,12 +10,18 @@ import {DataStructures} from "../../libraries/DataStructures.sol"; * @notice Lives on L1 and is used to pass messages into the rollup from L1. */ interface IInbox { - event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); + /** + * @notice Emitted when a message is sent + * @param l2BlockNumber - The L2 block number in which the message is included + * @param index - The index of the message in the block + * @param hash - The hash of the message + */ + event MessageSent(uint256 indexed l2BlockNumber, uint256 index, bytes32 hash); // docs:start:send_l1_to_l2_message /** * @notice Inserts a new message into the Inbox - * @dev Emits `LeafInserted` with data for easy access by the sequencer + * @dev Emits `MessageSent` with data for easy access by the sequencer * @param _recipient - The recipient of the message * @param _content - The content of the message (application specific) * @param _secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on L2) diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index 8a8e8d3a0e5..00367bf0319 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -8,22 +8,6 @@ pragma solidity >=0.8.18; * @notice Library that contains data structures used throughout the Aztec protocol */ library DataStructures { - // docs:start:data_structure_entry - /** - * @notice Entry struct - Done as struct to easily support extensions if needed - * @param fee - The fee provided to sequencer for including in the inbox. 0 if Outbox (as not applicable). - * @param count - The occurrence of the entry in the dataset - * @param version - The version of the entry - * @param deadline - The deadline to consume a message. Only after it, can a message be cancelled. - */ - struct Entry { - uint64 fee; - uint32 count; - uint32 version; - uint32 deadline; - } - // docs:end:data_structure_entry - // docs:start:l1_actor /** * @notice Actor on L1. diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 92e3006eb8b..7b47ffde25a 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -20,9 +20,9 @@ library Errors { error Outbox__Unauthorized(); // 0x2c9490c2 error Outbox__InvalidChainId(); // 0x577ec7c4 error Outbox__InvalidVersion(uint256 entry, uint256 message); // 0x7915cac3 - error Outbox__NothingToConsume(bytes32 entryKey); // 0xfb4fb506 + error Outbox__NothingToConsume(bytes32 messageHash); // 0xfb4fb506 error Outbox__IncompatibleEntryArguments( - bytes32 entryKey, + bytes32 messageHash, uint64 storedFee, uint64 feePassed, uint32 storedVersion, diff --git a/l1-contracts/src/core/libraries/MessageBox.sol b/l1-contracts/src/core/libraries/MessageBox.sol deleted file mode 100644 index dd20785c171..00000000000 --- a/l1-contracts/src/core/libraries/MessageBox.sol +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. -pragma solidity >=0.8.18; - -// Libraries -import {DataStructures} from "./DataStructures.sol"; -import {Errors} from "./Errors.sol"; - -/** - * @title MessageBox - * @author Aztec Labs - * @notice Library that implements multi-set logic for a mapping of entries (DataStructures.Entry) - * Allows for inserting, consuming, checking existence and fetching entries - * @dev This library is used by `Inbox` and `Outbox` to store messages - * @dev Allow passing of `_err` functions to allow for custom error messages dependent on the context of use - */ -library MessageBox { - /** - * @notice Inserts an entry into the MessageBox (multi-set) - * @dev Will increment the count of the entry if it already exists - * Will revert if the entry already exists with different fee or deadline - * @param _self - The storage mapping containing all entries - * @param _entryKey - The key to insert - * @param _fee - The fee to insert - * @param _deadline - The deadline to insert - * @param _err - A function taking _entryKey, _fee, _deadline as params that MUST revert with a error reason - * @dev The _err function is passed as a param to allow for custom error messages dependent on the context of use - * We use it to allow `Inbox` and `Outbox` to throw distinct errors - */ - function insert( - mapping(bytes32 entryKey => DataStructures.Entry entry) storage _self, - bytes32 _entryKey, - uint64 _fee, - uint32 _version, - uint32 _deadline, - function( - bytes32, - uint64, - uint64, - uint32, - uint32, - uint32, - uint32 - ) pure _err - ) internal { - DataStructures.Entry memory entry = _self[_entryKey]; - if ( - (entry.fee != 0 && entry.fee != _fee) || (entry.deadline != 0 && entry.deadline != _deadline) - || (entry.version != 0 && entry.version != _version) - ) { - // this should never happen as it is trying to overwrite `fee`, `version` and `deadline` with different values - // even though the entryKey (a hash) is the same! Pass all arguments to the error message for debugging. - _err(_entryKey, entry.fee, _fee, entry.version, _version, entry.deadline, _deadline); - } - entry.count += 1; - entry.fee = _fee; - entry.version = _version; - entry.deadline = _deadline; - _self[_entryKey] = entry; - } - - /** - * @notice Consume an entry if possible, reverts if nothing to consume - * @dev For multiplicity > 1, will consume one element - * @param _self - The storage mapping containing all entries - * @param _entryKey - The key to consume - * @param _err - A function taking _entryKey as param that MUST revert with a error reason - * @dev The _err function is passed as a param to allow for custom error messages dependent on the context of use - * We use it to allow `Inbox` and `Outbox` to throw distinct errors - */ - function consume( - mapping(bytes32 entryKey => DataStructures.Entry entry) storage _self, - bytes32 _entryKey, - function(bytes32) view _err - ) internal { - DataStructures.Entry storage entry = _self[_entryKey]; - if (entry.count == 0) _err(_entryKey); - entry.count--; - } - - /** - * @notice Check if an entry exists - * @param _self - The storage mapping containing all entries - * @param _entryKey - The key to lookup - * @return True if the entry exists, false otherwise - */ - function contains( - mapping(bytes32 entryKey => DataStructures.Entry entry) storage _self, - bytes32 _entryKey - ) internal view returns (bool) { - return _self[_entryKey].count > 0; - } - - /** - * @notice Fetch an entry - * @dev Will revert if the entry does not exist - * @param _self - The storage mapping containing all entries - * @param _entryKey - The key to lookup - * @param _err - A function taking _entryKey as param that MUST revert with a error reason - * @dev The _err function is passed as a param to allow for custom error messages dependent on the context of use - * We use it to allow `Inbox` and `Outbox` to throw distinct errors - * @return The entry matching the provided key - */ - function get( - mapping(bytes32 entryKey => DataStructures.Entry entry) storage _self, - bytes32 _entryKey, - function(bytes32) view _err - ) internal view returns (DataStructures.Entry memory) { - DataStructures.Entry memory entry = _self[_entryKey]; - if (entry.count == 0) _err(_entryKey); - return entry; - } -} diff --git a/l1-contracts/src/core/messagebridge/Inbox.sol b/l1-contracts/src/core/messagebridge/Inbox.sol index aa1a2959fe5..aaf5476a163 100644 --- a/l1-contracts/src/core/messagebridge/Inbox.sol +++ b/l1-contracts/src/core/messagebridge/Inbox.sol @@ -52,11 +52,11 @@ contract Inbox is IInbox { /** * @notice Inserts a new message into the Inbox - * @dev Emits `LeafInserted` with data for easy access by the sequencer + * @dev Emits `MessageSent` with data for easy access by the sequencer * @param _recipient - The recipient of the message * @param _content - The content of the message (application specific) * @param _secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on L2) - * @return The key of the message in the set + * @return Hash of the sent message. */ function sendL2Message( DataStructures.L2Actor memory _recipient, @@ -89,7 +89,7 @@ contract Inbox is IInbox { bytes32 leaf = message.sha256ToField(); uint256 index = currentTree.insertLeaf(leaf); - emit LeafInserted(inProgress, index, leaf); + emit MessageSent(inProgress, index, leaf); return leaf; } diff --git a/l1-contracts/test/Inbox.t.sol b/l1-contracts/test/Inbox.t.sol index a9f02c7f6a5..e7a0ca5af33 100644 --- a/l1-contracts/test/Inbox.t.sol +++ b/l1-contracts/test/Inbox.t.sol @@ -81,7 +81,7 @@ contract InboxTest is Test { bytes32 leaf = message.sha256ToField(); vm.expectEmit(true, true, true, true); // event we expect - emit IInbox.LeafInserted(FIRST_REAL_TREE_NUM, 0, leaf); + emit IInbox.MessageSent(FIRST_REAL_TREE_NUM, 0, leaf); // event we will get bytes32 insertedLeaf = inbox.sendL2Message(message.recipient, message.content, message.secretHash); diff --git a/l1-contracts/test/Registry.t.sol b/l1-contracts/test/Registry.t.sol index 49a6921f376..4bb4f44ddaf 100644 --- a/l1-contracts/test/Registry.t.sol +++ b/l1-contracts/test/Registry.t.sol @@ -9,7 +9,6 @@ import {Registry} from "../src/core/messagebridge/Registry.sol"; import {Errors} from "../src/core/libraries/Errors.sol"; import {DataStructures} from "../src/core/libraries/DataStructures.sol"; -import {MessageBox} from "../src/core/libraries/MessageBox.sol"; contract RegistryTest is Test { address internal constant DEAD = address(0xdead); diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index 8ec35f3db7d..550afbe5bc8 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -26,7 +26,7 @@ contract TokenPortalTest is Test { uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; - event MessageConsumed(bytes32 indexed entryKey, address indexed recipient); + event MessageConsumed(bytes32 indexed messageHash, address indexed recipient); Registry internal registry; @@ -114,7 +114,7 @@ contract TokenPortalTest is Test { // Check the event was emitted vm.expectEmit(true, true, true, true); // event we expect - emit IInbox.LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); + emit IInbox.MessageSent(FIRST_REAL_TREE_NUM, 0, expectedLeaf); // event we will get // Perform op @@ -139,7 +139,7 @@ contract TokenPortalTest is Test { // Check the event was emitted vm.expectEmit(true, true, true, true); // event we expect - emit IInbox.LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); + emit IInbox.MessageSent(FIRST_REAL_TREE_NUM, 0, expectedLeaf); // Perform op bytes32 leaf = tokenPortal.depositToAztecPublic(to, amount, secretHashForL2MessageConsumption); diff --git a/l1-contracts/test/portals/UniswapPortal.sol b/l1-contracts/test/portals/UniswapPortal.sol index 8eb22e31163..2fad905b7e9 100644 --- a/l1-contracts/test/portals/UniswapPortal.sol +++ b/l1-contracts/test/portals/UniswapPortal.sol @@ -53,7 +53,7 @@ contract UniswapPortal { * @param _aztecRecipient - The aztec address to receive the output assets * @param _secretHashForL1ToL2Message - The hash of the secret consumable message. The hash should be 254 bits (so it can fit in a Field element) * @param _withCaller - When true, using `msg.sender` as the caller, otherwise address(0) - * @return The entryKey of the deposit transaction in the Inbox + * @return A hash of the L1 to L2 message inserted in the Inbox */ function swapPublic( address _inputTokenPortal, @@ -160,7 +160,7 @@ contract UniswapPortal { * @param _secretHashForRedeemingMintedNotes - The hash of the secret to redeem minted notes privately on Aztec. The hash should be 254 bits (so it can fit in a Field element) * @param _secretHashForL1ToL2Message - The hash of the secret consumable message. The hash should be 254 bits (so it can fit in a Field element) * @param _withCaller - When true, using `msg.sender` as the caller, otherwise address(0) - * @return The entryKey of the deposit transaction in the Inbox + * @return A hash of the L1 to L2 message inserted in the Inbox */ function swapPrivate( address _inputTokenPortal, diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index d1abc1de5e6..b525e78a494 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -23,8 +23,6 @@ import {UniswapPortal} from "./UniswapPortal.sol"; contract UniswapPortalTest is Test { using Hash for DataStructures.L2ToL1Msg; - event L1ToL2MessageCancelled(bytes32 indexed entryKey); - IERC20 public constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 public constant WETH9 = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); @@ -152,14 +150,14 @@ contract UniswapPortalTest is Test { } function _addMessagesToOutbox( - bytes32 daiWithdrawEntryKey, - bytes32 swapEntryKey, + bytes32 daiWithdrawMessageHash, + bytes32 swapMessageHash, uint256 _l2BlockNumber ) internal returns (bytes32, bytes32[] memory, bytes32[] memory) { uint256 treeHeight = 1; NaiveMerkle tree = new NaiveMerkle(treeHeight); - tree.insertLeaf(daiWithdrawEntryKey); - tree.insertLeaf(swapEntryKey); + tree.insertLeaf(daiWithdrawMessageHash); + tree.insertLeaf(swapMessageHash); bytes32 treeRoot = tree.computeRoot(); (bytes32[] memory withdrawSiblingPath,) = tree.computeSiblingPath(0); @@ -286,14 +284,14 @@ contract UniswapPortalTest is Test { function testRevertIfSwapParamsDifferentToOutboxMessage() public { uint256 l2BlockNumber = 69; - bytes32 daiWithdrawEntryKey = + bytes32 daiWithdrawMessageHash = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + bytes32 swapMessageHash = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + _addMessagesToOutbox(daiWithdrawMessageHash, swapMessageHash, l2BlockNumber); bytes32 newAztecRecipient = bytes32(uint256(0x4)); - bytes32 entryKeyPortalChecksAgainst = + bytes32 messageHashPortalChecksAgainst = _createUniswapSwapMessagePublic(newAztecRecipient, address(this)); bytes32 actualRoot; @@ -302,13 +300,13 @@ contract UniswapPortalTest is Test { { uint256 treeHeight = 1; NaiveMerkle tree1 = new NaiveMerkle(treeHeight); - tree1.insertLeaf(daiWithdrawEntryKey); - tree1.insertLeaf(swapEntryKey); + tree1.insertLeaf(daiWithdrawMessageHash); + tree1.insertLeaf(swapMessageHash); actualRoot = tree1.computeRoot(); NaiveMerkle tree2 = new NaiveMerkle(treeHeight); - tree2.insertLeaf(daiWithdrawEntryKey); - tree2.insertLeaf(entryKeyPortalChecksAgainst); + tree2.insertLeaf(daiWithdrawMessageHash); + tree2.insertLeaf(messageHashPortalChecksAgainst); consumedRoot = tree2.computeRoot(); } @@ -317,7 +315,7 @@ contract UniswapPortalTest is Test { Errors.MerkleLib__InvalidRoot.selector, actualRoot, consumedRoot, - entryKeyPortalChecksAgainst, + messageHashPortalChecksAgainst, 1 ) ); @@ -351,12 +349,12 @@ contract UniswapPortalTest is Test { function testSwapWithDesignatedCaller() public { uint256 l2BlockNumber = 69; - bytes32 daiWithdrawEntryKey = + bytes32 daiWithdrawMessageHash = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + bytes32 swapMessageHash = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + _addMessagesToOutbox(daiWithdrawMessageHash, swapMessageHash, l2BlockNumber); PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ PortalDataStructures.OutboxMessageMetadata({ @@ -397,13 +395,13 @@ contract UniswapPortalTest is Test { vm.assume(_caller != address(uniswapPortal)); uint256 l2BlockNumber = 69; - bytes32 daiWithdrawEntryKey = + bytes32 daiWithdrawMessageHash = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); // don't set caller on swapPublic() -> so anyone can call this method. - bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); + bytes32 swapMessageHash = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + _addMessagesToOutbox(daiWithdrawMessageHash, swapMessageHash, l2BlockNumber); PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ PortalDataStructures.OutboxMessageMetadata({ @@ -445,12 +443,12 @@ contract UniswapPortalTest is Test { vm.assume(_caller != address(this)); uint256 l2BlockNumber = 69; - bytes32 daiWithdrawEntryKey = + bytes32 daiWithdrawMessageHash = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + bytes32 swapMessageHash = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + _addMessagesToOutbox(daiWithdrawMessageHash, swapMessageHash, l2BlockNumber); PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ PortalDataStructures.OutboxMessageMetadata({ @@ -466,7 +464,8 @@ contract UniswapPortalTest is Test { ]; vm.startPrank(_caller); - bytes32 entryKeyPortalChecksAgainst = _createUniswapSwapMessagePublic(aztecRecipient, _caller); + bytes32 messageHashPortalChecksAgainst = + _createUniswapSwapMessagePublic(aztecRecipient, _caller); bytes32 actualRoot; bytes32 consumedRoot; @@ -474,13 +473,13 @@ contract UniswapPortalTest is Test { { uint256 treeHeight = 1; NaiveMerkle tree1 = new NaiveMerkle(treeHeight); - tree1.insertLeaf(daiWithdrawEntryKey); - tree1.insertLeaf(swapEntryKey); + tree1.insertLeaf(daiWithdrawMessageHash); + tree1.insertLeaf(swapMessageHash); actualRoot = tree1.computeRoot(); NaiveMerkle tree2 = new NaiveMerkle(treeHeight); - tree2.insertLeaf(daiWithdrawEntryKey); - tree2.insertLeaf(entryKeyPortalChecksAgainst); + tree2.insertLeaf(daiWithdrawMessageHash); + tree2.insertLeaf(messageHashPortalChecksAgainst); consumedRoot = tree2.computeRoot(); } @@ -489,7 +488,7 @@ contract UniswapPortalTest is Test { Errors.MerkleLib__InvalidRoot.selector, actualRoot, consumedRoot, - entryKeyPortalChecksAgainst, + messageHashPortalChecksAgainst, 1 ) ); @@ -506,18 +505,18 @@ contract UniswapPortalTest is Test { outboxMessageMetadata ); - entryKeyPortalChecksAgainst = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); + messageHashPortalChecksAgainst = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); { uint256 treeHeight = 1; NaiveMerkle tree1 = new NaiveMerkle(treeHeight); - tree1.insertLeaf(daiWithdrawEntryKey); - tree1.insertLeaf(swapEntryKey); + tree1.insertLeaf(daiWithdrawMessageHash); + tree1.insertLeaf(swapMessageHash); actualRoot = tree1.computeRoot(); NaiveMerkle tree2 = new NaiveMerkle(treeHeight); - tree2.insertLeaf(daiWithdrawEntryKey); - tree2.insertLeaf(entryKeyPortalChecksAgainst); + tree2.insertLeaf(daiWithdrawMessageHash); + tree2.insertLeaf(messageHashPortalChecksAgainst); consumedRoot = tree2.computeRoot(); } vm.expectRevert( @@ -525,7 +524,7 @@ contract UniswapPortalTest is Test { Errors.MerkleLib__InvalidRoot.selector, actualRoot, consumedRoot, - entryKeyPortalChecksAgainst, + messageHashPortalChecksAgainst, 1 ) ); @@ -546,13 +545,13 @@ contract UniswapPortalTest is Test { function testRevertIfSwapMessageWasForDifferentPublicOrPrivateFlow() public { uint256 l2BlockNumber = 69; - bytes32 daiWithdrawEntryKey = + bytes32 daiWithdrawMessageHash = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); // Create message for `_isPrivateFlow`: - bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + bytes32 swapMessageHash = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + _addMessagesToOutbox(daiWithdrawMessageHash, swapMessageHash, l2BlockNumber); PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ PortalDataStructures.OutboxMessageMetadata({ @@ -567,7 +566,7 @@ contract UniswapPortalTest is Test { }) ]; - bytes32 entryKeyPortalChecksAgainst = + bytes32 messageHashPortalChecksAgainst = _createUniswapSwapMessagePrivate(secretHashForRedeemingMintedNotes, address(this)); bytes32 actualRoot; @@ -576,13 +575,13 @@ contract UniswapPortalTest is Test { { uint256 treeHeight = 1; NaiveMerkle tree1 = new NaiveMerkle(treeHeight); - tree1.insertLeaf(daiWithdrawEntryKey); - tree1.insertLeaf(swapEntryKey); + tree1.insertLeaf(daiWithdrawMessageHash); + tree1.insertLeaf(swapMessageHash); actualRoot = tree1.computeRoot(); NaiveMerkle tree2 = new NaiveMerkle(treeHeight); - tree2.insertLeaf(daiWithdrawEntryKey); - tree2.insertLeaf(entryKeyPortalChecksAgainst); + tree2.insertLeaf(daiWithdrawMessageHash); + tree2.insertLeaf(messageHashPortalChecksAgainst); consumedRoot = tree2.computeRoot(); } @@ -591,7 +590,7 @@ contract UniswapPortalTest is Test { Errors.MerkleLib__InvalidRoot.selector, actualRoot, consumedRoot, - entryKeyPortalChecksAgainst, + messageHashPortalChecksAgainst, 1 ) ); diff --git a/noir-projects/aztec-nr/aztec/src/messaging.nr b/noir-projects/aztec-nr/aztec/src/messaging.nr index 958a5e863f4..4cfe82baa0c 100644 --- a/noir-projects/aztec-nr/aztec/src/messaging.nr +++ b/noir-projects/aztec-nr/aztec/src/messaging.nr @@ -23,15 +23,15 @@ pub fn process_l1_to_l2_message( content, secret ); - let entry_key = msg.hash(); + let message_hash = msg.hash(); - let returned_message = get_l1_to_l2_membership_witness(entry_key); + let returned_message = get_l1_to_l2_membership_witness(message_hash); let leaf_index = returned_message[0]; let sibling_path = arr_copy_slice(returned_message, [0; L1_TO_L2_MSG_TREE_HEIGHT], 1); // Check that the message is in the tree // This is implicitly checking that the values of the message are correct - let root = compute_merkle_root(entry_key, leaf_index, sibling_path); + let root = compute_merkle_root(message_hash, leaf_index, sibling_path); assert(root == l1_to_l2_root, "Message not in state"); msg.compute_nullifier() diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr index de73fca0c49..0f9e98eeaa9 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr @@ -1,9 +1,9 @@ use dep::protocol_types::constants::L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH; -// Checks if a msg is within the l1ToL2Msg tree +// Obtains membership witness (index and sibling path) for a message in the L1 to L2 message tree. #[oracle(getL1ToL2MembershipWitness)] -fn get_l1_to_l2_membership_witness_oracle(_entry_key: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] {} +fn get_l1_to_l2_membership_witness_oracle(_message_hash: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] {} -unconstrained pub fn get_l1_to_l2_membership_witness(entry_key: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] { - get_l1_to_l2_membership_witness_oracle(entry_key) +unconstrained pub fn get_l1_to_l2_membership_witness(message_hash: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] { + get_l1_to_l2_membership_witness_oracle(message_hash) } diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index 7754448a3f0..48471c74aa3 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -46,14 +46,14 @@ describe('Archiver', () => { publicClient.getBlockNumber.mockResolvedValueOnce(2500n).mockResolvedValueOnce(2600n).mockResolvedValueOnce(2700n); // logs should be created in order of how archiver syncs. publicClient.getLogs - .mockResolvedValueOnce([makeLeafInsertedEvent(98n, 1n, 0n), makeLeafInsertedEvent(99n, 1n, 1n)]) + .mockResolvedValueOnce([makeMessageSentEvent(98n, 1n, 0n), makeMessageSentEvent(99n, 1n, 1n)]) .mockResolvedValueOnce([makeTxsPublishedEvent(101n, blocks[0].body.getTxsEffectsHash())]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) .mockResolvedValueOnce([ - makeLeafInsertedEvent(2504n, 2n, 0n), - makeLeafInsertedEvent(2505n, 2n, 1n), - makeLeafInsertedEvent(2505n, 2n, 2n), - makeLeafInsertedEvent(2506n, 3n, 1n), + makeMessageSentEvent(2504n, 2n, 0n), + makeMessageSentEvent(2505n, 2n, 1n), + makeMessageSentEvent(2505n, 2n, 2n), + makeMessageSentEvent(2506n, 3n, 1n), ]) .mockResolvedValueOnce([ makeTxsPublishedEvent(2510n, blocks[1].body.getTxsEffectsHash()), @@ -142,7 +142,7 @@ describe('Archiver', () => { publicClient.getBlockNumber.mockResolvedValue(102n); // add all of the L1 to L2 messages to the mock publicClient.getLogs - .mockResolvedValueOnce([makeLeafInsertedEvent(66n, 1n, 0n), makeLeafInsertedEvent(68n, 1n, 1n)]) + .mockResolvedValueOnce([makeMessageSentEvent(66n, 1n, 0n), makeMessageSentEvent(68n, 1n, 1n)]) .mockResolvedValueOnce([ makeTxsPublishedEvent(70n, blocks[0].body.getTxsEffectsHash()), makeTxsPublishedEvent(80n, blocks[1].body.getTxsEffectsHash()), @@ -196,21 +196,21 @@ function makeTxsPublishedEvent(l1BlockNum: bigint, txsEffectsHash: Buffer) { } /** - * Makes fake L1ToL2 LeafInserted events for testing purposes. + * Makes fake L1ToL2 MessageSent events for testing purposes. * @param l1BlockNum - L1 block number. - * @param l2BlockNumber - The L2 block number of the leaf inserted. - * @returns LeafInserted event logs. + * @param l2BlockNumber - The L2 block number of in which the message was included. + * @returns MessageSent event logs. */ -function makeLeafInsertedEvent(l1BlockNum: bigint, l2BlockNumber: bigint, index: bigint) { +function makeMessageSentEvent(l1BlockNum: bigint, l2BlockNumber: bigint, index: bigint) { return { blockNumber: l1BlockNum, args: { - blockNumber: l2BlockNumber, + l2BlockNumber, index, - value: Fr.random().toString(), + hash: Fr.random().toString(), }, transactionHash: `0x${l1BlockNum}`, - } as Log; + } as Log; } /** diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 19760bfee3b..72eb746663b 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -148,10 +148,13 @@ export class Archiver implements ArchiveSource { * * This code does not handle reorgs. */ - const lastL1Blocks = await this.store.getSynchedL1BlockNumbers(); + const l1SynchPoint = await this.store.getSynchPoint(); const currentL1BlockNumber = await this.publicClient.getBlockNumber(); - if (currentL1BlockNumber <= lastL1Blocks.blocks && currentL1BlockNumber <= lastL1Blocks.messages) { + if ( + currentL1BlockNumber <= l1SynchPoint.blocksSynchedTo && + currentL1BlockNumber <= l1SynchPoint.messagesSynchedTo + ) { // chain hasn't moved forward // or it's been rolled back return; @@ -184,14 +187,14 @@ export class Archiver implements ArchiveSource { this.publicClient, this.inboxAddress, blockUntilSynced, - lastL1Blocks.messages + 1n, + l1SynchPoint.messagesSynchedTo + 1n, currentL1BlockNumber, ); if (retrievedL1ToL2Messages.retrievedData.length !== 0) { this.log( `Retrieved ${retrievedL1ToL2Messages.retrievedData.length} new L1 -> L2 messages between L1 blocks ${ - lastL1Blocks.messages + 1n + l1SynchPoint.messagesSynchedTo + 1n } and ${currentL1BlockNumber}.`, ); } @@ -205,7 +208,7 @@ export class Archiver implements ArchiveSource { this.publicClient, this.availabilityOracleAddress, blockUntilSynced, - lastL1Blocks.blocks + 1n, + l1SynchPoint.blocksSynchedTo + 1n, currentL1BlockNumber, ); @@ -220,7 +223,7 @@ export class Archiver implements ArchiveSource { this.publicClient, this.rollupAddress, blockUntilSynced, - lastL1Blocks.blocks + 1n, + l1SynchPoint.blocksSynchedTo + 1n, currentL1BlockNumber, nextExpectedL2BlockNum, ); @@ -244,7 +247,7 @@ export class Archiver implements ArchiveSource { } else { this.log( `Retrieved ${blocks.length} new L2 blocks between L1 blocks ${ - lastL1Blocks.blocks + 1n + l1SynchPoint.blocksSynchedTo + 1n } and ${currentL1BlockNumber}.`, ); } diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 20793bb76bc..2adacfa03ee 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -20,10 +20,10 @@ import { DataRetrieval } from './data_retrieval.js'; * Represents the latest L1 block processed by the archiver for various objects in L2. */ export type ArchiverL1SynchPoint = { - /** The last L1 block that added a new L2 block. */ - blocks: bigint; - /** The last L1 block that added L1 -> L2 messages from the Inbox. */ - messages: bigint; + /** Number of the last L1 block that added a new L2 block. */ + blocksSynchedTo: bigint; + /** Number of the last L1 block that added L1 -> L2 messages from the Inbox. */ + messagesSynchedTo: bigint; }; /** @@ -134,7 +134,7 @@ export interface ArchiverDataStore { /** * Gets the synch point of the archiver */ - getSynchedL1BlockNumbers(): Promise; + getSynchPoint(): Promise; /** * Add new contract classes from an L2 block to the store's list. diff --git a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts index 606acf74aa9..ad454ab0d6f 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -81,19 +81,19 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); }); - describe('getSynchedL1BlockNumbers', () => { + describe('getSynchPoint', () => { it('returns 0n if no blocks have been added', async () => { - await expect(store.getSynchedL1BlockNumbers()).resolves.toEqual({ - blocks: 0n, - messages: 0n, + await expect(store.getSynchPoint()).resolves.toEqual({ + blocksSynchedTo: 0n, + messagesSynchedTo: 0n, }); }); it('returns the L1 block number in which the most recent L2 block was published', async () => { await store.addBlocks(blocks); - await expect(store.getSynchedL1BlockNumbers()).resolves.toEqual({ - blocks: blocks.lastProcessedL1BlockNumber, - messages: 0n, + await expect(store.getSynchPoint()).resolves.toEqual({ + blocksSynchedTo: blocks.lastProcessedL1BlockNumber, + messagesSynchedTo: 0n, }); }); @@ -102,9 +102,9 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch lastProcessedL1BlockNumber: 1n, retrievedData: [new InboxLeaf(0n, 0n, Fr.ZERO)], }); - await expect(store.getSynchedL1BlockNumbers()).resolves.toEqual({ - blocks: 0n, - messages: 1n, + await expect(store.getSynchPoint()).resolves.toEqual({ + blocksSynchedTo: 0n, + messagesSynchedTo: 1n, }); }); }); diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index ec4a8820b33..86f1fc6e8bf 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -6,10 +6,10 @@ import { PublicClient } from 'viem'; import { getL2BlockProcessedLogs, - getLeafInsertedLogs, + getMessageSentLogs, getTxsPublishedLogs, processL2BlockProcessedLogs, - processLeafInsertedLogs, + processMessageSentLogs, processTxsPublishedLogs, } from './eth_log_handlers.js'; @@ -132,14 +132,14 @@ export async function retrieveL1ToL2Messages( if (searchStartBlock > searchEndBlock) { break; } - const leafInsertedLogs = await getLeafInsertedLogs(publicClient, inboxAddress, searchStartBlock, searchEndBlock); - if (leafInsertedLogs.length === 0) { + const messageSentLogs = await getMessageSentLogs(publicClient, inboxAddress, searchStartBlock, searchEndBlock); + if (messageSentLogs.length === 0) { break; } - const l1ToL2Messages = processLeafInsertedLogs(leafInsertedLogs); + const l1ToL2Messages = processMessageSentLogs(messageSentLogs); retrievedL1ToL2Messages.push(...l1ToL2Messages); // handles the case when there are no new messages: - searchStartBlock = (leafInsertedLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n; + searchStartBlock = (messageSentLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n; } while (blockUntilSynced && searchStartBlock <= searchEndBlock); return { lastProcessedL1BlockNumber: searchStartBlock - 1n, retrievedData: retrievedL1ToL2Messages }; } diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index c3380efd8a5..4c04f3f4410 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -8,17 +8,17 @@ import { AvailabilityOracleAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts' import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hexToBytes } from 'viem'; /** - * Processes newly received LeafInserted (L1 to L2) logs. - * @param logs - LeafInserted logs. - * @returns Array of all processed LeafInserted logs + * Processes newly received MessageSent (L1 to L2) logs. + * @param logs - MessageSent logs. + * @returns Array of all processed MessageSent logs */ -export function processLeafInsertedLogs( - logs: Log[], +export function processMessageSentLogs( + logs: Log[], ): InboxLeaf[] { const leaves: InboxLeaf[] = []; for (const log of logs) { - const { blockNumber, index, value } = log.args; - leaves.push(new InboxLeaf(blockNumber, index, Fr.fromString(value))); + const { l2BlockNumber, index, hash } = log.args; + leaves.push(new InboxLeaf(l2BlockNumber, index, Fr.fromString(hash))); } return leaves; } @@ -191,24 +191,24 @@ export function getTxsPublishedLogs( } /** - * Get relevant `LeafInserted` logs emitted by Inbox on chain. + * Get relevant `MessageSent` logs emitted by Inbox on chain. * @param publicClient - The viem public client to use for transaction retrieval. * @param inboxAddress - The address of the inbox contract. * @param fromBlock - First block to get logs from (inclusive). * @param toBlock - Last block to get logs from (inclusive). - * @returns An array of `LeafInserted` logs. + * @returns An array of `MessageSent` logs. */ -export function getLeafInsertedLogs( +export function getMessageSentLogs( publicClient: PublicClient, inboxAddress: EthAddress, fromBlock: bigint, toBlock: bigint, -): Promise[]> { +): Promise[]> { return publicClient.getLogs({ address: getAddress(inboxAddress.toString()), event: getAbiItem({ abi: InboxAbi, - name: 'LeafInserted', + name: 'MessageSent', }), fromBlock, toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts index b5d9fa6fc36..e183b68076b 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts @@ -214,12 +214,10 @@ export class KVArchiverDataStore implements ArchiverDataStore { /** * Gets the last L1 block number processed by the archiver */ - getSynchedL1BlockNumbers(): Promise { - const blocks = this.#blockStore.getSynchedL1BlockNumber(); - const messages = this.#messageStore.getSynchedL1BlockNumber(); + getSynchPoint(): Promise { return Promise.resolve({ - blocks, - messages, + blocksSynchedTo: this.#blockStore.getSynchedL1BlockNumber(), + messagesSynchedTo: this.#messageStore.getSynchedL1BlockNumber(), }); } } diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts index 3cae18ea47b..cec550cec18 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts @@ -11,8 +11,7 @@ import { Fr } from '@aztec/foundation/fields'; */ export class L1ToL2MessageStore { /** - * A map containing the entry key to the corresponding L1 to L2 - * messages (and the number of times the message has been seen). + * A map pointing from a key in a "blockNum-messageIndex" format to the corresponding L1 to L2 message hash. */ protected store: Map = new Map(); diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts index ae701859282..12c8922e0b2 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts @@ -357,10 +357,10 @@ export class MemoryArchiverStore implements ArchiverDataStore { return Promise.resolve(this.l2BlockContexts[this.l2BlockContexts.length - 1].block.number); } - public getSynchedL1BlockNumbers(): Promise { + public getSynchPoint(): Promise { return Promise.resolve({ - blocks: this.lastL1BlockNewBlocks, - messages: this.lastL1BlockNewMessages, + blocksSynchedTo: this.lastL1BlockNewBlocks, + messagesSynchedTo: this.lastL1BlockNewMessages, }); } } diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 43a1aefd8bc..657668e07e4 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -424,10 +424,10 @@ export class AztecNodeService implements AztecNode { * @param l2ToL1Message - The l2ToL1Message get the index / sibling path for. * @returns A tuple of the index and the sibling path of the L2ToL1Message. */ - public async getL2ToL1MessageIndexAndSiblingPath( + public async getL2ToL1MessageMembershipWitness( blockNumber: L2BlockNumber, l2ToL1Message: Fr, - ): Promise<[number, SiblingPath]> { + ): Promise<[bigint, SiblingPath]> { const block = await this.blockSource.getBlock(blockNumber === 'latest' ? await this.getBlockNumber() : blockNumber); if (block === undefined) { @@ -440,11 +440,11 @@ export class AztecNodeService implements AztecNode { throw new Error('L2 to L1 Messages are not padded'); } - const indexOfL2ToL1Message = l2ToL1Messages.findIndex(l2ToL1MessageInBlock => - l2ToL1MessageInBlock.equals(l2ToL1Message), + const indexOfL2ToL1Message = BigInt( + l2ToL1Messages.findIndex(l2ToL1MessageInBlock => l2ToL1MessageInBlock.equals(l2ToL1Message)), ); - if (indexOfL2ToL1Message === -1) { + if (indexOfL2ToL1Message === -1n) { throw new Error('The L2ToL1Message you are trying to prove inclusion of does not exist'); } @@ -453,7 +453,7 @@ export class AztecNodeService implements AztecNode { const tree = new StandardTree(openTmpStore(true), new SHA256Trunc(), 'temp_outhash_sibling_path', treeHeight); await tree.appendLeaves(l2ToL1Messages.map(l2ToL1Msg => l2ToL1Msg.toBuffer())); - return [indexOfL2ToL1Message, await tree.getSiblingPath(BigInt(indexOfL2ToL1Message), true)]; + return [indexOfL2ToL1Message, await tree.getSiblingPath(indexOfL2ToL1Message, true)]; } /** diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index 619208b8400..738692cf30a 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -77,18 +77,19 @@ export interface AztecNode { isL1ToL2MessageSynced(l1ToL2Message: Fr): Promise; /** - * Returns the index of a l2ToL1Message in a ephemeral l2 to l1 data tree as well as its sibling path. + * Returns a membership witness of an l2ToL1Message in an ephemeral l2 to l1 message tree. + * @dev Membership witness is a consists of the index and the sibling path of the l2ToL1Message. * @remarks This tree is considered ephemeral because it is created on-demand by: taking all the l2ToL1 messages * in a single block, and then using them to make a variable depth append-only tree with these messages as leaves. * The tree is discarded immediately after calculating what we need from it. * @param blockNumber - The block number at which to get the data. - * @param l2ToL1Message - The l2ToL1Message get the index / sibling path for. + * @param l2ToL1Message - The l2ToL1Message to get the membership witness for. * @returns A tuple of the index and the sibling path of the L2ToL1Message. */ - getL2ToL1MessageIndexAndSiblingPath( + getL2ToL1MessageMembershipWitness( blockNumber: L2BlockNumber, l2ToL1Message: Fr, - ): Promise<[number, SiblingPath]>; + ): Promise<[bigint, SiblingPath]>; /** * Returns a sibling path for a leaf in the committed historic blocks tree. diff --git a/yarn-project/circuit-types/src/messaging/inbox_leaf.ts b/yarn-project/circuit-types/src/messaging/inbox_leaf.ts index eff95b07d0a..f0b507cfb92 100644 --- a/yarn-project/circuit-types/src/messaging/inbox_leaf.ts +++ b/yarn-project/circuit-types/src/messaging/inbox_leaf.ts @@ -8,7 +8,7 @@ export class InboxLeaf { public readonly blockNumber: bigint, /** Index of the leaf in L2 block message subtree. */ public readonly index: bigint, - /** Leaf in the subtree. */ + /** Leaf in the subtree/message hash. */ public readonly leaf: Fr, ) {} 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 248162c52ce..491ba12e26e 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 @@ -26,10 +26,6 @@ export class L1ToL2Message { * The hash of the spending secret. */ public readonly secretHash: Fr, - /** - * The entry key for the message - optional. - */ - public readonly entryKey?: Fr, ) {} /** @@ -70,7 +66,7 @@ export class L1ToL2Message { return new L1ToL2Message(L1Actor.empty(), L2Actor.empty(), Fr.ZERO, Fr.ZERO); } - static random(entryKey?: Fr): L1ToL2Message { - return new L1ToL2Message(L1Actor.random(), L2Actor.random(), Fr.random(), Fr.random(), entryKey); + static random(): L1ToL2Message { + return new L1ToL2Message(L1Actor.random(), L2Actor.random(), Fr.random(), Fr.random()); } } 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 d337897f3bd..c87579abff7 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 @@ -82,14 +82,14 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); // 2. Deposit tokens to the TokenPortal - const msgLeaf = await crossChainTestHarness.sendTokensToPortalPrivate( + const msgHash = await crossChainTestHarness.sendTokensToPortalPrivate( secretHashForRedeemingMintedNotes, bridgeAmount, secretHashForL2MessageConsumption, ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); // 3. Consume L1 -> L2 message and mint private tokens on L2 await crossChainTestHarness.consumeMessageOnAztecAndMintPrivately( @@ -119,7 +119,7 @@ describe('e2e_cross_chain_messaging', () => { const l2TxReceipt = await crossChainTestHarness.withdrawPrivateFromAztecToL1(withdrawAmount, nonce); await crossChainTestHarness.expectPrivateBalanceOnL2(ownerAddress, bridgeAmount - withdrawAmount); - const [l2ToL1MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [l2ToL1MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( l2TxReceipt.blockNumber!, l2ToL1Message, ); @@ -146,7 +146,7 @@ describe('e2e_cross_chain_messaging', () => { crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - const msgLeaf = await crossChainTestHarness.sendTokensToPortalPrivate( + const msgHash = await crossChainTestHarness.sendTokensToPortalPrivate( secretHashForRedeemingMintedNotes, bridgeAmount, secretHashForL2MessageConsumption, @@ -154,7 +154,7 @@ describe('e2e_cross_chain_messaging', () => { expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); // Wait for the message to be available for consumption - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); // 3. Consume L1 -> L2 message and mint private tokens on L2 const content = toTruncField( @@ -178,7 +178,7 @@ describe('e2e_cross_chain_messaging', () => { .withWallet(user2Wallet) .methods.claim_private(secretHashForL2MessageConsumption, bridgeAmount, secretForL2MessageConsumption) .simulate(), - ).rejects.toThrow(`No L1 to L2 message found for entry key ${wrongMessage.hash().toString()}`); + ).rejects.toThrow(`No L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); // send the right one - const consumptionReceipt = await l2Bridge @@ -227,7 +227,7 @@ describe('e2e_cross_chain_messaging', () => { const [secretForL2MessageConsumption, secretHashForL2MessageConsumption] = crossChainTestHarness.generateClaimSecret(); - const msgLeaf = await crossChainTestHarness.sendTokensToPortalPrivate( + const msgHash = await crossChainTestHarness.sendTokensToPortalPrivate( Fr.random(), bridgeAmount, secretHashForL2MessageConsumption, @@ -235,7 +235,7 @@ describe('e2e_cross_chain_messaging', () => { expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(0n); // Wait for the message to be available for consumption - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); const content = toTruncField( sha256( 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 98f1f3e655e..ca3dd3af8b3 100644 --- a/yarn-project/end-to-end/src/e2e_outbox.test.ts +++ b/yarn-project/end-to-end/src/e2e_outbox.test.ts @@ -67,36 +67,36 @@ describe('E2E Outbox Tests', () => { // the index to match the order of the block we obtained earlier. We also then use this sibling path to hash up to the root, // verifying that the expected root obtained through the message and the sibling path match the actual root // that was returned by the circuits in the header as out_hash. - const [index, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [index, siblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( txReceipt.blockNumber!, l2ToL1Messages![0], ); expect(siblingPath.pathSize).toBe(2); - expect(index).toBe(0); + expect(index).toBe(0n); const expectedRoot = calculateExpectedRoot(l2ToL1Messages![0], siblingPath as SiblingPath<2>, index); expect(expectedRoot.toString('hex')).toEqual(block?.header.contentCommitment.outHash.toString('hex')); - const [index2, siblingPath2] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [index2, siblingPath2] = await aztecNode.getL2ToL1MessageMembershipWitness( txReceipt.blockNumber!, l2ToL1Messages![1], ); expect(siblingPath2.pathSize).toBe(2); - expect(index2).toBe(1); + expect(index2).toBe(1n); const expectedRoot2 = calculateExpectedRoot(l2ToL1Messages![1], siblingPath2 as SiblingPath<2>, index2); expect(expectedRoot2.toString('hex')).toEqual(block?.header.contentCommitment.outHash.toString('hex')); }, 360_000); - function calculateExpectedRoot(l2ToL1Message: Fr, siblingPath: SiblingPath<2>, index: number): Buffer { + function calculateExpectedRoot(l2ToL1Message: Fr, siblingPath: SiblingPath<2>, index: bigint): Buffer { const firstLayerInput: [Buffer, Buffer] = - index & 0x1 + index & 0x1n ? [siblingPath.toBufferArray()[0], l2ToL1Message.toBuffer()] : [l2ToL1Message.toBuffer(), siblingPath.toBufferArray()[0]]; const firstLayer = merkleSha256.hash(...firstLayerInput); - index /= 2; + index /= 2n; // In the circuit, the 'firstLayer' is the kernel out hash, which is truncated to 31 bytes // To match the result, the below preimages and the output are truncated to 31 then padded const secondLayerInput: [Buffer, Buffer] = - index & 0x1 + index & 0x1n ? [siblingPath.toBufferArray()[1], truncateAndPad(firstLayer)] : [truncateAndPad(firstLayer), siblingPath.toBufferArray()[1]]; return truncateAndPad(merkleSha256.hash(...secondLayerInput)); 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 581e2e603c4..2dbfa75bc6d 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 @@ -89,11 +89,11 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); // 2. Deposit tokens to the TokenPortal - const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgHash = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); // Wait for the message to be available for consumption - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); // 3. Consume L1 -> L2 message and mint public tokens on L2 await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, secret); @@ -122,7 +122,7 @@ describe('e2e_public_cross_chain_messaging', () => { // Check balance before and after exit. expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - const [l2ToL1MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [l2ToL1MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( l2TxReceipt.blockNumber!, l2ToL1Message, ); @@ -147,10 +147,10 @@ describe('e2e_public_cross_chain_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgHash = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); const content = toTruncField( sha256( @@ -200,10 +200,10 @@ describe('e2e_public_cross_chain_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(bridgeAmount); - const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgHash = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(0n); - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); // Wrong message hash const content = toTruncField( @@ -223,7 +223,7 @@ describe('e2e_public_cross_chain_messaging', () => { await expect( l2Bridge.withWallet(user2Wallet).methods.claim_private(secretHash, bridgeAmount, secret).simulate(), - ).rejects.toThrow(`No L1 to L2 message found for entry key ${wrongMessage.hash().toString()}`); + ).rejects.toThrow(`No L1 to L2 message found for message hash ${wrongMessage.hash().toString()}`); }, 60_000); // Note: We register one portal address when deploying contract but that address is no-longer the only address @@ -272,7 +272,7 @@ describe('e2e_public_cross_chain_messaging', () => { ), )[0]; - const [l2MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [l2MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( l2TxReceipt.blockNumber!, leaf, ); @@ -343,7 +343,7 @@ describe('e2e_public_cross_chain_messaging', () => { ); // We check that the message was correctly injected by checking the emitted event - const msgLeaf = message.hash(); + const msgHash = message.hash(); { const txReceipt = await crossChainTestHarness.publicClient.waitForTransactionReceipt({ hash: txHash, @@ -359,13 +359,13 @@ describe('e2e_public_cross_chain_messaging', () => { data: txLog.data, topics: txLog.topics, }); - const receivedMsgLeaf = topics.args.value; + const receivedMsgHash = topics.args.hash; // We check that the leaf inserted into the subtree matches the expected message hash - expect(receivedMsgLeaf).toBe(msgLeaf.toString()); + expect(receivedMsgHash).toBe(msgHash.toString()); } - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); // Finally, e consume the L1 -> L2 message using the test contract either from private or public if (isPrivate) { diff --git a/yarn-project/end-to-end/src/e2e_public_to_private_messaging.test.ts b/yarn-project/end-to-end/src/e2e_public_to_private_messaging.test.ts index 78473915a3e..0b67d07c67d 100644 --- a/yarn-project/end-to-end/src/e2e_public_to_private_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_public_to_private_messaging.test.ts @@ -48,10 +48,10 @@ describe('e2e_public_to_private_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgHash = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await underlyingERC20.read.balanceOf([ethAccount.toString()])).toBe(l1TokenBalance - bridgeAmount); - await crossChainTestHarness.makeMessageConsumable(msgLeaf); + await crossChainTestHarness.makeMessageConsumable(msgHash); await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, secret); await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount); 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 d6a568def0b..7dea048cdcb 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 @@ -215,7 +215,7 @@ describe('L1Publisher integration', () => { topics: txLog.topics, }); - return Fr.fromString(topics.args.value); + return Fr.fromString(topics.args.hash); }; /** 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 0453e64f68b..5d2fbc75ada 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 @@ -255,13 +255,13 @@ export class CrossChainTestHarness { // Deposit tokens to the TokenPortal this.logger('Sending messages to L1 portal to be consumed publicly'); const args = [this.ownerAddress.toString(), bridgeAmount, secretHash.toString()] as const; - const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { + const { result: messageHash } = await this.tokenPortal.simulate.depositToAztecPublic(args, { account: this.ethAccount.toString(), } as any); const txHash2 = await this.tokenPortal.write.depositToAztecPublic(args, {} as any); await this.publicClient.waitForTransactionReceipt({ hash: txHash2 }); - return Fr.fromString(entryKeyHex); + return Fr.fromString(messageHash); } async sendTokensToPortalPrivate( @@ -281,13 +281,13 @@ export class CrossChainTestHarness { bridgeAmount, secretHashForL2MessageConsumption.toString(), ] as const; - const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { + const { result: messageHash } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { account: this.ethAccount.toString(), } as any); const txHash2 = await this.tokenPortal.write.depositToAztecPrivate(args, {} as any); await this.publicClient.waitForTransactionReceipt({ hash: txHash2 }); - return Fr.fromString(entryKeyHex); + return Fr.fromString(messageHash); } async mintTokensPublicOnL2(amount: bigint) { @@ -392,17 +392,17 @@ export class CrossChainTestHarness { async withdrawFundsFromBridgeOnL1( withdrawAmount: bigint, blockNumber: number, - messageIndex: number, + messageIndex: bigint, siblingPath: SiblingPath, ) { - this.logger('Send L1 tx to consume entry and withdraw funds'); + this.logger('Send L1 tx to consume message and withdraw funds'); // Call function on L1 contract to consume the message const { request: withdrawRequest } = await this.tokenPortal.simulate.withdraw([ this.ethAccount.toString(), withdrawAmount, false, BigInt(blockNumber), - BigInt(messageIndex), + messageIndex, siblingPath.toBufferArray().map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], ]); @@ -463,9 +463,9 @@ export class CrossChainTestHarness { * the message is sent to Inbox and when the subtree containing the message is included in the block and then when * it's included it becomes available for consumption in the next block because the l1 to l2 message tree. */ - async makeMessageConsumable(msgLeaf: Fr) { + async makeMessageConsumable(msgHash: Fr) { // We poll isL1ToL2MessageSynced endpoint until the message is available - await retryUntil(async () => await this.aztecNode.isL1ToL2MessageSynced(msgLeaf), 'message sync', 10); + await retryUntil(async () => await this.aztecNode.isL1ToL2MessageSynced(msgHash), 'message sync', 10); await this.mintTokensPublicOnL2(0n); await this.mintTokensPublicOnL2(0n); diff --git a/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts b/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts index 585c5626856..ef5140df02f 100644 --- a/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts +++ b/yarn-project/end-to-end/src/shared/gas_portal_test_harness.ts @@ -151,12 +151,12 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { // Deposit tokens to the TokenPortal this.logger('Sending messages to L1 portal to be consumed publicly'); const args = [l2Address.toString(), bridgeAmount, secretHash.toString()] as const; - const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { + const { result: messageHash } = await this.tokenPortal.simulate.depositToAztecPublic(args, { account: this.ethAccount.toString(), } as any); await this.tokenPortal.write.depositToAztecPublic(args, {} as any); - return Fr.fromString(entryKeyHex); + return Fr.fromString(messageHash); } async sendTokensToPortalPrivate( @@ -177,12 +177,12 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { deadline, secretHashForL2MessageConsumption.toString(), ] as const; - const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { + const { result: messageHash } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { account: this.ethAccount.toString(), } as any); await this.tokenPortal.write.depositToAztecPrivate(args, {} as any); - return Fr.fromString(entryKeyHex); + return Fr.fromString(messageHash); } async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, owner: AztecAddress, secret: Fr) { 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 7f4aed845eb..61c270341f1 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 @@ -179,7 +179,7 @@ export const uniswapL1L2TestSuite = ( const [secretForMintingWeth, secretHashForMintingWeth] = wethCrossChainHarness.generateClaimSecret(); const [secretForRedeemingWeth, secretHashForRedeemingWeth] = wethCrossChainHarness.generateClaimSecret(); - const tokenDepositMsgLeaf = await wethCrossChainHarness.sendTokensToPortalPrivate( + const tokenDepositMsgHash = await wethCrossChainHarness.sendTokensToPortalPrivate( secretHashForRedeemingWeth, wethAmountToBridge, secretHashForMintingWeth, @@ -192,7 +192,7 @@ export const uniswapL1L2TestSuite = ( wethAmountToBridge, ); - await wethCrossChainHarness.makeMessageConsumable(tokenDepositMsgLeaf); + await wethCrossChainHarness.makeMessageConsumable(tokenDepositMsgHash); // 2. Claim WETH on L2 logger('Minting weth on L2'); @@ -317,11 +317,11 @@ export const uniswapL1L2TestSuite = ( daiCrossChainHarness.tokenPortalAddress, ); - const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( l2UniswapInteractionReceipt.blockNumber!, swapPrivateLeaf, ); - const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( l2UniswapInteractionReceipt.blockNumber!, withdrawLeaf, ); @@ -358,7 +358,7 @@ export const uniswapL1L2TestSuite = ( const txHash = await uniswapPortal.write.swapPrivate(swapArgs, {} as any); // We get the msg leaf from event so that we can later wait for it to be available for consumption - let tokenOutMsgLeaf: Fr; + let tokenOutMsgHash: Fr; { const txReceipt = await daiCrossChainHarness.publicClient.waitForTransactionReceipt({ hash: txHash, @@ -370,7 +370,7 @@ export const uniswapL1L2TestSuite = ( data: txLog.data, topics: txLog.topics, }); - tokenOutMsgLeaf = Fr.fromString(topics.args.value); + tokenOutMsgHash = Fr.fromString(topics.args.hash); } // weth was swapped to dai and send to portal @@ -381,7 +381,7 @@ export const uniswapL1L2TestSuite = ( const daiAmountToBridge = BigInt(daiL1BalanceOfPortalAfter - daiL1BalanceOfPortalBeforeSwap); // Wait for the message to be available for consumption - await daiCrossChainHarness.makeMessageConsumable(tokenOutMsgLeaf); + await daiCrossChainHarness.makeMessageConsumable(tokenOutMsgHash); // 6. claim dai on L2 logger('Consuming messages to mint dai on L2'); @@ -411,7 +411,7 @@ export const uniswapL1L2TestSuite = ( // 1. Approve and deposit weth to the portal and move to L2 const [secretForMintingWeth, secretHashForMintingWeth] = wethCrossChainHarness.generateClaimSecret(); - const wethDepositMsgLeaf = await wethCrossChainHarness.sendTokensToPortalPublic( + const wethDepositMsgHash = await wethCrossChainHarness.sendTokensToPortalPublic( wethAmountToBridge, secretHashForMintingWeth, ); @@ -424,7 +424,7 @@ export const uniswapL1L2TestSuite = ( ); // Wait for the message to be available for consumption - await wethCrossChainHarness.makeMessageConsumable(wethDepositMsgLeaf); + await wethCrossChainHarness.makeMessageConsumable(wethDepositMsgHash); // 2. Claim WETH on L2 logger('Minting weth on L2'); @@ -552,11 +552,11 @@ export const uniswapL1L2TestSuite = ( daiCrossChainHarness.tokenPortalAddress, ); - const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( uniswapL2Interaction.blockNumber!, swapPublicLeaf, ); - const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( uniswapL2Interaction.blockNumber!, withdrawLeaf, ); @@ -593,7 +593,7 @@ export const uniswapL1L2TestSuite = ( const txHash = await uniswapPortal.write.swapPublic(swapArgs, {} as any); // We get the msg leaf from event so that we can later wait for it to be available for consumption - let outTokenDepositMsgLeaf: Fr; + let outTokenDepositMsgHash: Fr; { const txReceipt = await daiCrossChainHarness.publicClient.waitForTransactionReceipt({ hash: txHash, @@ -605,7 +605,7 @@ export const uniswapL1L2TestSuite = ( data: txLog.data, topics: txLog.topics, }); - outTokenDepositMsgLeaf = Fr.fromString(topics.args.value); + outTokenDepositMsgHash = Fr.fromString(topics.args.hash); } // weth was swapped to dai and send to portal @@ -616,7 +616,7 @@ export const uniswapL1L2TestSuite = ( const daiAmountToBridge = BigInt(daiL1BalanceOfPortalAfter - daiL1BalanceOfPortalBeforeSwap); // Wait for the message to be available for consumption - await daiCrossChainHarness.makeMessageConsumable(outTokenDepositMsgLeaf); + await daiCrossChainHarness.makeMessageConsumable(outTokenDepositMsgHash); // 6. claim dai on L2 logger('Consuming messages to mint dai on L2'); @@ -919,11 +919,11 @@ export const uniswapL1L2TestSuite = ( ), )[0]; - const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( withdrawReceipt.blockNumber!, swapPrivateLeaf, ); - const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( withdrawReceipt.blockNumber!, withdrawLeaf, ); @@ -1058,11 +1058,11 @@ export const uniswapL1L2TestSuite = ( ), )[0]; - const [swapPublicL2MessageIndex, swapPublicSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [swapPublicL2MessageIndex, swapPublicSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( withdrawReceipt.blockNumber!, swapPublicLeaf, ); - const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( withdrawReceipt.blockNumber!, withdrawLeaf, ); diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index ff524c63f99..d0b5ac16837 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -121,17 +121,14 @@ export class SimulatorOracle implements DBOracle { } /** - * Retrieves the L1ToL2Message associated with a specific entry key - * - * @throws If the entry key is not found - * @param entryKey - The key of the message to be retrieved - * @returns A promise that resolves to the message data, a sibling path and the - * index of the message in the l1ToL2MessageTree + * Fetches the a message from the db, given its key. + * @param messageHash - Hash of the message. + * @returns The l1 to l2 membership witness (index of message in the tree and sibling path). */ - async getL1ToL2MembershipWitness(entryKey: Fr): Promise> { - const response = await this.aztecNode.getL1ToL2MessageMembershipWitness('latest', entryKey); + async getL1ToL2MembershipWitness(messageHash: Fr): Promise> { + const response = await this.aztecNode.getL1ToL2MessageMembershipWitness('latest', messageHash); if (!response) { - throw new Error(`No L1 to L2 message found for entry key ${entryKey.toString()}`); + throw new Error(`No L1 to L2 message found for message hash ${messageHash.toString()}`); } const [index, siblingPath] = response; return new MessageLoadOracleInputs(index, siblingPath); diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index c93c6d7e6c8..6008f8b2aa5 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -224,11 +224,11 @@ export class WorldStateDB implements CommitmentsDB { } public async getL1ToL2MembershipWitness( - entryKey: Fr, + messageHash: Fr, ): Promise> { - const index = (await this.db.findLeafIndex(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, entryKey.toBuffer()))!; + const index = (await this.db.findLeafIndex(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, messageHash.toBuffer()))!; if (index === undefined) { - throw new Error(`Message ${entryKey.toString()} not found`); + throw new Error(`Message ${messageHash.toString()} not found`); } const siblingPath = await this.db.getSiblingPath( MerkleTreeId.L1_TO_L2_MESSAGE_TREE, diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 17510858cfc..78f7f2abbc2 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -244,8 +244,8 @@ export class Oracle { return toACVMField(exists); } - async getL1ToL2MembershipWitness([entryKey]: ACVMField[]): Promise { - const message = await this.typedOracle.getL1ToL2MembershipWitness(fromACVMField(entryKey)); + async getL1ToL2MembershipWitness([messageHash]: ACVMField[]): Promise { + const message = await this.typedOracle.getL1ToL2MembershipWitness(fromACVMField(messageHash)); return message.toFields().map(toACVMField); } diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 83a75f7d339..e2fc9040bd1 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -171,7 +171,7 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('checkNullifierExists'); } - getL1ToL2MembershipWitness(_entryKey: Fr): Promise> { + getL1ToL2MembershipWitness(_messageHash: Fr): Promise> { throw new OracleMethodNotAvailableError('getL1ToL2MembershipWitness'); } diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 40707da52b7..64e06296f82 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -226,11 +226,11 @@ export class ViewDataOracle extends TypedOracle { /** * Fetches the a message from the db, given its key. - * @param entryKey - A buffer representing the entry key. - * @returns The l1 to l2 message data + * @param messageHash - Hash of the message. + * @returns The l1 to l2 membership witness (index of message in the tree and sibling path). */ - public async getL1ToL2MembershipWitness(entryKey: Fr) { - return await this.db.getL1ToL2MembershipWitness(entryKey); + public async getL1ToL2MembershipWitness(messageHash: Fr) { + return await this.db.getL1ToL2MembershipWitness(messageHash); } /** diff --git a/yarn-project/simulator/src/public/db.ts b/yarn-project/simulator/src/public/db.ts index 54f1f1d4cbe..8f7524bff1f 100644 --- a/yarn-project/simulator/src/public/db.ts +++ b/yarn-project/simulator/src/public/db.ts @@ -79,12 +79,12 @@ export interface PublicContractsDB { /** Database interface for providing access to commitment tree, l1 to l2 message tree, and nullifier tree. */ export interface CommitmentsDB { /** - * Gets a confirmed L1 to L2 message for the given entry key. + * Gets a confirmed L1 to L2 message for the given message hash. * TODO(Maddiaa): Can be combined with aztec-node method that does the same thing. - * @param entryKey - The entry key. - * @returns - The l1 to l2 message object + * @param messageHash - Hash of the message. + * @returns The l1 to l2 membership witness (index of message in the tree and sibling path). */ - getL1ToL2MembershipWitness(entryKey: Fr): Promise>; + getL1ToL2MembershipWitness(messageHash: Fr): Promise>; /** * Gets the index of a commitment in the note hash tree. diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index dffd03f579a..31e9eb1ee88 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -93,11 +93,11 @@ export class PublicExecutionContext extends TypedOracle { /** * Fetches the a message from the db, given its key. - * @param entryKey - A buffer representing the entry key. + * @param messageHash - Hash of the massage. * @returns The l1 to l2 message data */ - public async getL1ToL2MembershipWitness(entryKey: Fr) { - return await this.commitmentsDb.getL1ToL2MembershipWitness(entryKey); + public async getL1ToL2MembershipWitness(messageHash: Fr) { + return await this.commitmentsDb.getL1ToL2MembershipWitness(messageHash); } /** From 0a3ec3d2239c02c1fc96ed935bc5100cba4d145c Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 22 Mar 2024 13:31:13 +0000 Subject: [PATCH 26/36] fix --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 99c3a2e7872..a03e22625b5 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -122,9 +122,8 @@ pub fn get_notes( // failure if malicious oracle injects 0 nonce here for a "pre-existing" note. context.push_note_hash_read_request(note_hash_for_read_request); - // The below code is used to collapse a sparse array into one where the values are guaranteed to be at the front of the array - // We write at returned_notes + // We write at returned_notes[num_notes] because num_notes is only advanced when we have a value in opt_notes returned_notes[num_notes] = Option::some(note); num_notes += 1; }; From a4c86a0ffd2754e455bd423dee0777de7729b094 Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Fri, 22 Mar 2024 08:55:54 -0500 Subject: [PATCH 27/36] Update note_getter.nr --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a03e22625b5..45aa922705b 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -100,7 +100,7 @@ pub fn get_notes( storage_slot: Field, options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { - let mut opt_notes = get_notes_internal(storage_slot, options); + let opt_notes = get_notes_internal(storage_slot, options); let mut returned_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut num_notes = 0; From ed51191b276f033a7d857b1e6463720698f29196 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 27 Mar 2024 14:53:19 +0000 Subject: [PATCH 28/36] fix fix fix --- noir-projects/aztec-nr/Nargo.toml | 1 + .../aztec-nr/aztec/src/note/note_getter.nr | 15 ++- noir-projects/aztec-nr/tests/Nargo.toml | 9 ++ noir-projects/aztec-nr/tests/src/lib.nr | 2 + noir-projects/aztec-nr/tests/src/mock.nr | 3 + .../aztec-nr/tests/src/mock/test_note.nr | 67 ++++++++++ .../aztec-nr/tests/src/note_getter_test.nr | 124 ++++++++++++++++++ .../end-to-end/src/e2e_note_getter.test.ts | 22 ---- 8 files changed, 219 insertions(+), 24 deletions(-) create mode 100644 noir-projects/aztec-nr/tests/Nargo.toml create mode 100644 noir-projects/aztec-nr/tests/src/lib.nr create mode 100644 noir-projects/aztec-nr/tests/src/mock.nr create mode 100644 noir-projects/aztec-nr/tests/src/mock/test_note.nr create mode 100644 noir-projects/aztec-nr/tests/src/note_getter_test.nr diff --git a/noir-projects/aztec-nr/Nargo.toml b/noir-projects/aztec-nr/Nargo.toml index b799d8221ef..94e4674f336 100644 --- a/noir-projects/aztec-nr/Nargo.toml +++ b/noir-projects/aztec-nr/Nargo.toml @@ -8,4 +8,5 @@ members = [ "field-note", "slow-updates-tree", "value-note", + "tests", ] 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 890a8318aa7..e123dc8ddf0 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -2,13 +2,14 @@ use dep::protocol_types::{ constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH -} + } }; use crate::context::PrivateContext; use crate::note::{ + note_header::NoteHeader, note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_consumption + utils::compute_note_hash_for_consumption, }; use crate::oracle; @@ -101,6 +102,16 @@ pub fn get_notes( options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let opt_notes = get_notes_internal(storage_slot, options); + + _get_notes_constrain_get_notes_internal(context, storage_slot, opt_notes, options) +} + +pub fn _get_notes_constrain_get_notes_internal( + context: &mut PrivateContext, + storage_slot: Field, + opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], + options: NoteGetterOptions +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let mut returned_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut num_notes = 0; diff --git a/noir-projects/aztec-nr/tests/Nargo.toml b/noir-projects/aztec-nr/tests/Nargo.toml new file mode 100644 index 00000000000..13404b37324 --- /dev/null +++ b/noir-projects/aztec-nr/tests/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "tests" +authors = ["aztec-labs"] +compiler_version = ">=0.18.0" +type = "lib" + +[dependencies] +aztec = { path = "../aztec" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } diff --git a/noir-projects/aztec-nr/tests/src/lib.nr b/noir-projects/aztec-nr/tests/src/lib.nr new file mode 100644 index 00000000000..1856bb3ba68 --- /dev/null +++ b/noir-projects/aztec-nr/tests/src/lib.nr @@ -0,0 +1,2 @@ +mod note_getter_test; +mod mock; diff --git a/noir-projects/aztec-nr/tests/src/mock.nr b/noir-projects/aztec-nr/tests/src/mock.nr new file mode 100644 index 00000000000..c48b029f940 --- /dev/null +++ b/noir-projects/aztec-nr/tests/src/mock.nr @@ -0,0 +1,3 @@ +mod test_note; + +use test_note::TestNote; diff --git a/noir-projects/aztec-nr/tests/src/mock/test_note.nr b/noir-projects/aztec-nr/tests/src/mock/test_note.nr new file mode 100644 index 00000000000..17a9ba69333 --- /dev/null +++ b/noir-projects/aztec-nr/tests/src/mock/test_note.nr @@ -0,0 +1,67 @@ +use dep::aztec::context::PrivateContext; +use dep::aztec::note::{ + note_header::NoteHeader, + note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, + note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, + utils::compute_note_hash_for_consumption, + note_getter::_get_notes_constrain_get_notes_internal, +}; + +global TEST_NOTE_LENGTH = 1; + +struct TestNote { + header: NoteHeader, + value: Field, +} + +impl NoteInterface for TestNote { + fn serialize_content(self) -> [Field; TEST_NOTE_LENGTH] { + [self.value] + } + + fn deserialize_content(fields: [Field; TEST_NOTE_LENGTH]) -> Self { + Self { + value: fields[0], + header: NoteHeader::empty(), + } + } + + fn compute_note_content_hash(self) -> Field { + 0 + } + + fn get_header(self) -> NoteHeader { + self.header + } + + fn set_header(&mut self, header: NoteHeader) -> () { + self.header = header; + } + + fn get_note_type_id() -> Field { + 0 + } + + fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { + 0 + } + + fn compute_nullifier_without_context(self) -> Field { + 0 + } + + fn broadcast(self, context: &mut PrivateContext, slot: Field) { + assert( + false, "TestNote does not support broadcast." + ); + } +} + +impl TestNote { + pub fn new(value: Field) -> Self { + TestNote { + value, + header: NoteHeader::empty(), + } + } +} diff --git a/noir-projects/aztec-nr/tests/src/note_getter_test.nr b/noir-projects/aztec-nr/tests/src/note_getter_test.nr new file mode 100644 index 00000000000..da9640ab731 --- /dev/null +++ b/noir-projects/aztec-nr/tests/src/note_getter_test.nr @@ -0,0 +1,124 @@ +use dep::protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL; +use dep::aztec::context::PrivateContext; +use dep::aztec::note::{ + note_header::NoteHeader, + note_getter_options::{NoteGetterOptions, Sort, SortOrder, Comparator, PropertySelector}, + note_getter::_get_notes_constrain_get_notes_internal, +}; +use dep::aztec::protocol_types::address::AztecAddress; +use crate::mock::test_note::TestNote; + +#[test] +fn sets_note_manually_and_fetches_it() { + let mut context: PrivateContext = dep::std::unsafe::zeroed(); + context.inputs.call_context.storage_contract_address = AztecAddress::from_field(69); + + let mut test_note = TestNote::new(1337); + test_note.header = NoteHeader::new(AztecAddress::from_field(69), 0, 42); + + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + opt_notes[0] = Option::some(test_note); + + let storage_slot: Field = 42; + + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + opt_notes[0] = Option::some(test_note); + + let mut options = NoteGetterOptions::new(); + let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); + assert_eq(returned[0].unwrap().value, 1337); +} + +#[test(should_fail)] +fn cannot_return_zero_notes() { + let mut context: PrivateContext = dep::std::unsafe::zeroed(); + let storage_slot: Field = 0; + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + + let mut options = NoteGetterOptions::new(); + let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); +} + +#[test(should_fail)] +fn mismatched_address() { + let mut context: PrivateContext = dep::std::unsafe::zeroed(); + context.inputs.call_context.storage_contract_address = AztecAddress::from_field(1); + + let storage_slot: Field = 0; + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + opt_notes[0] = Option::some(TestNote::new(1)); + + let mut options = NoteGetterOptions::new(); + let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); +} + +#[test(should_fail)] +fn mismatched_storage_slot() { + let mut context: PrivateContext = dep::std::unsafe::zeroed(); + context.inputs.call_context.storage_contract_address = AztecAddress::from_field(1); + + let mut test_note = TestNote::new(1); + test_note.header = NoteHeader::new(AztecAddress::from_field(1), 0, 1); + + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + opt_notes[0] = Option::some(test_note); + + let storage_slot: Field = 0; + + let mut options = NoteGetterOptions::new(); + let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); +} + +#[test(should_fail)] +fn invalid_selector() { + let mut context: PrivateContext = dep::std::unsafe::zeroed(); + context.inputs.call_context.storage_contract_address = AztecAddress::from_field(1); + + let mut test_note = TestNote::new(1); + test_note.header = NoteHeader::new(AztecAddress::from_field(1), 0, 0); + + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + opt_notes[0] = Option::some(test_note); + + let storage_slot: Field = 0; + + let mut options = NoteGetterOptions::new().select(PropertySelector { index: 0, offset: 0, length: 32 }, 10, Option::some(Comparator.EQ)); + let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); +} + +#[test(should_fail)] +fn invalid_note_order() { + let mut context: PrivateContext = dep::std::unsafe::zeroed(); + + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + opt_notes[0] = Option::some(TestNote::new(1)); + opt_notes[1] = Option::some(TestNote::new(2)); + + let storage_slot: Field = 0; + + let mut options = NoteGetterOptions::new().sort(PropertySelector { index: 0, offset: 0, length: 32 }, SortOrder.DESC); + let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); +} + +#[test] +fn sparse_notes_array() { + let mut context: PrivateContext = dep::std::unsafe::zeroed(); + + let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + opt_notes[1] = Option::some(TestNote::new(0)); + opt_notes[2] = Option::some(TestNote::new(1)); + opt_notes[3] = Option::some(TestNote::new(2)); + opt_notes[5] = Option::some(TestNote::new(3)); + opt_notes[8] = Option::some(TestNote::new(4)); + opt_notes[11] = Option::some(TestNote::new(5)); + opt_notes[19] = Option::some(TestNote::new(6)); + + let storage_slot: Field = 0; + + let mut options = NoteGetterOptions::new(); + let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); + + for i in 0..7 { + assert(returned[i].unwrap().value == i as Field); + } +} diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 9406521fff3..fdd740be676 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -253,28 +253,6 @@ describe('e2e_note_getter', () => { expect(viewNotesManyResult).toEqual(getNotesManyResult); expect(viewNotesManyResult.sort()).toEqual([BigInt(VALUE), BigInt(VALUE + 1)]); }, 45_000); - - it('get_notes should collapse sparse arrays', async () => { - // We call the function that creates a sparse array in get_notes_internal, using the filter - // It then gets the notes from the set and confirms that the array is not sparse and has been handled by get_notes - const tx = await contract.methods.create_and_get_many_notes_with_filter().send().wait(); - const block = await aztecNode.getBlock(tx.blockNumber!); - - // We want to verify that there are: - // 2 tx's in the block - expect(block!.body.unencryptedLogs.txLogs.length).toStrictEqual(2); - // our first tx has two function logs - expect(block?.body.unencryptedLogs.txLogs[0].functionLogs.length).toStrictEqual(2); - // our second function logs has 7 individual logs that were emitted from create_and_get_notes_many_with_filter - expect(block!.body.unencryptedLogs.txLogs[0].functionLogs[1].logs.length).toStrictEqual(7); - - const unencryptedLogs = block?.body.unencryptedLogs.txLogs.flatMap(txLog => - txLog.functionLogs.flatMap(functionLog => - functionLog.logs.map(log => log.toString('hex').substring(log.length * 2 - 2)), - ), - ); - expect(unencryptedLogs).toStrictEqual(['00', '01', '02', '03', '04', '05', '06']); - }, 45_000); }); }); }); From a8f26344907594b9d85ae29dbbc8edb60e4e7215 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 27 Mar 2024 16:15:08 +0000 Subject: [PATCH 29/36] cleanup --- .../contracts/test_contract/src/main.nr | 38 ------------------- .../end-to-end/src/e2e_note_getter.test.ts | 3 +- 2 files changed, 1 insertion(+), 40 deletions(-) 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 bf4b7813c54..24311d27087 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -130,44 +130,6 @@ contract Test { emit_unencrypted_log_from_private(&mut context, opt_notes[1].unwrap().value); } - pub fn filter_that_creates_sparse_array( - notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], - _args: bool - ) -> pub [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { - // selected is our returned sparse array - let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; - - selected[1] = notes[0]; - selected[2] = notes[1]; - selected[3] = notes[2]; - selected[5] = notes[3]; - selected[8] = notes[4]; - selected[13] = notes[5]; - selected[21] = notes[6]; - - selected - } - - #[aztec(private)] - pub fn create_and_get_many_notes_with_filter() { - // We create 7 notes to test getting them later - for i in 0..7 { - let mut note = FieldNote::new(i as Field); - storage.example_set.insert(&mut note, false); - } - - let options = NoteGetterOptions::with_filter(filter_that_creates_sparse_array, true); - // get_notes should collapse this array - let opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = storage.example_set.get_notes(options); - - // We can't get the return value of a private function from the outside world in an end to end test, so we - // expose it via an unecrypted log instead. - for i in 0..7 { - // We verify that the array was collapsed by unwrapping the first 7 values. - emit_unencrypted_log_from_private(&mut context, opt_notes[i].unwrap().value); - } - } - unconstrained fn call_view_notes(storage_slot: Field, active_or_nullified: bool) -> pub Field { assert( storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index fdd740be676..57903aba281 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -16,12 +16,11 @@ function unwrapOptions(options: NoirOption[]): T[] { } describe('e2e_note_getter', () => { - let aztecNode: AztecNode; let wallet: Wallet; let teardown: () => Promise; beforeAll(async () => { - ({ teardown, wallet, aztecNode } = await setup()); + ({ teardown, wallet } = await setup()); }, 25_000); afterAll(() => teardown()); From 0c710581f555a49f619bcadc70a75ce101032b22 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 27 Mar 2024 16:15:33 +0000 Subject: [PATCH 30/36] cleanup --- yarn-project/end-to-end/src/e2e_note_getter.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 57903aba281..402b50f5b05 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -1,4 +1,4 @@ -import { AztecAddress, AztecNode, Comparator, Fr, Wallet, toBigInt } from '@aztec/aztec.js'; +import { AztecAddress, Comparator, Fr, Wallet, toBigInt } from '@aztec/aztec.js'; import { DocsExampleContract, TestContract } from '@aztec/noir-contracts.js'; import { setup } from './fixtures/utils.js'; From 52ec4f6fbc6a42ae46c6351c7669f2399eff5078 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 27 Mar 2024 16:36:03 +0000 Subject: [PATCH 31/36] addressing comments --- noir-projects/aztec-nr/aztec/src/note/note_getter.nr | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 e123dc8ddf0..37070983d73 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -1,12 +1,11 @@ use dep::protocol_types::{ constants::{ - MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH, - MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH, + MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH } }; use crate::context::PrivateContext; use crate::note::{ - note_header::NoteHeader, note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_consumption, From a3a34a394ddb87637790e43b67da2c3a4622cee8 Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:41:07 -0500 Subject: [PATCH 32/36] Update noir-projects/aztec-nr/tests/src/note_getter_test.nr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Beneš --- noir-projects/aztec-nr/tests/src/note_getter_test.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/tests/src/note_getter_test.nr b/noir-projects/aztec-nr/tests/src/note_getter_test.nr index da9640ab731..999ddd3b44a 100644 --- a/noir-projects/aztec-nr/tests/src/note_getter_test.nr +++ b/noir-projects/aztec-nr/tests/src/note_getter_test.nr @@ -16,7 +16,7 @@ fn sets_note_manually_and_fetches_it() { let mut test_note = TestNote::new(1337); test_note.header = NoteHeader::new(AztecAddress::from_field(69), 0, 42); - let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; + let mut opt_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; opt_notes[0] = Option::some(test_note); let storage_slot: Field = 42; From 1c3fc6ec9e79222cb3e274867c3be6eceeb73643 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 27 Mar 2024 16:46:14 +0000 Subject: [PATCH 33/36] fmt --- noir-projects/aztec-nr/authwit/src/account.nr | 16 +++++-- .../context/inputs/private_context_inputs.nr | 5 +- .../aztec/src/context/public_context.nr | 3 +- noir-projects/aztec-nr/aztec/src/deploy.nr | 4 +- .../aztec/src/history/contract_inclusion.nr | 47 +++++++------------ .../aztec-nr/aztec/src/initializer.nr | 20 ++++---- noir-projects/aztec-nr/aztec/src/messaging.nr | 9 +++- .../aztec-nr/aztec/src/note/note_getter.nr | 8 ++-- .../oracle/enqueue_public_function_call.nr | 3 +- .../oracle/get_l1_to_l2_membership_witness.nr | 17 ++++--- .../aztec-nr/aztec/src/oracle/logs.nr | 14 +++--- .../aztec-nr/aztec/src/oracle/unsafe_rand.nr | 1 - .../aztec-nr/aztec/src/state_vars/map.nr | 2 +- .../aztec/src/state_vars/private_immutable.nr | 2 +- .../aztec/src/state_vars/private_mutable.nr | 2 +- .../aztec/src/state_vars/public_mutable.nr | 2 +- .../aztec-nr/tests/src/mock/test_note.nr | 10 ++-- .../aztec-nr/tests/src/note_getter_test.nr | 13 +++-- 18 files changed, 96 insertions(+), 82 deletions(-) diff --git a/noir-projects/aztec-nr/authwit/src/account.nr b/noir-projects/aztec-nr/authwit/src/account.nr index b8a62fb6653..2e33c4a0823 100644 --- a/noir-projects/aztec-nr/authwit/src/account.nr +++ b/noir-projects/aztec-nr/authwit/src/account.nr @@ -1,6 +1,6 @@ use dep::aztec::context::{PrivateContext, PublicContext, Context}; use dep::aztec::state_vars::{Map, PublicMutable}; -use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector, hash::{pedersen_hash}}; +use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector, hash::pedersen_hash}; use crate::entrypoint::{app::AppPayload, fee::FeePayload}; use crate::auth::{IS_VALID_SELECTOR, compute_outer_authwit_hash}; @@ -76,7 +76,12 @@ impl AccountActions { // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can // consume the message. // This ensures that contracts cannot consume messages that are not intended for them. - let message_hash = compute_outer_authwit_hash(context.msg_sender(), context.chain_id(), context.version(), inner_hash); + let message_hash = compute_outer_authwit_hash( + context.msg_sender(), + context.chain_id(), + context.version(), + inner_hash + ); let valid_fn = self.is_valid_impl; assert(valid_fn(context, message_hash) == true, "Message not authorized by account"); context.push_new_nullifier(message_hash, 0); @@ -90,7 +95,12 @@ impl AccountActions { // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can // consume the message. // This ensures that contracts cannot consume messages that are not intended for them. - let message_hash = compute_outer_authwit_hash(context.msg_sender(), context.chain_id(), context.version(), inner_hash); + let message_hash = compute_outer_authwit_hash( + context.msg_sender(), + context.chain_id(), + context.version(), + inner_hash + ); let is_valid = self.approved_action.at(message_hash).read(); assert(is_valid == true, "Message not authorized by account"); context.push_new_nullifier(message_hash, 0); diff --git a/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr b/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr index 4d1e8e0e0dd..79523b9affc 100644 --- a/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr +++ b/noir-projects/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr @@ -1,7 +1,4 @@ -use dep::protocol_types::{ - abis::call_context::CallContext, - header::Header -}; +use dep::protocol_types::{abis::call_context::CallContext, header::Header}; use crate::context::globals::private_global_variables::PrivateGlobalVariables; // PrivateContextInputs are expected to be provided to each private function 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 1d2789d9a2c..d3fc1490ff4 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -15,7 +15,8 @@ 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, 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_array, header::Header, messaging::l2_to_l1_message::L2ToL1Message, diff --git a/noir-projects/aztec-nr/aztec/src/deploy.nr b/noir-projects/aztec-nr/aztec/src/deploy.nr index 6f75d3edef0..60f7fef0620 100644 --- a/noir-projects/aztec-nr/aztec/src/deploy.nr +++ b/noir-projects/aztec-nr/aztec/src/deploy.nr @@ -8,7 +8,9 @@ pub fn deploy_contract(context: &mut PrivateContext, target: AztecAddress) { let universal_deploy = instance.deployer.is_zero(); if !universal_deploy { - assert(instance.deployer == context.this_address(), "Deployer address does not match current address"); + assert( + instance.deployer == context.this_address(), "Deployer address does not match current address" + ); } // Adapted from noir-contracts/contracts/contract_instance_deployer_contract/src/interface/ContractInstanceDeployer.nr diff --git a/noir-projects/aztec-nr/aztec/src/history/contract_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/contract_inclusion.nr index 1a16ea986c7..cb14ef1b06a 100644 --- a/noir-projects/aztec-nr/aztec/src/history/contract_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/contract_inclusion.nr @@ -1,49 +1,40 @@ use dep::protocol_types::{ - address::{AztecAddress, EthAddress}, - contract_class_id::ContractClassId, - grumpkin_point::GrumpkinPoint, - hash::silo_nullifier, - constants::DEPLOYER_CONTRACT_ADDRESS + address::{AztecAddress, EthAddress}, contract_class_id::ContractClassId, + grumpkin_point::GrumpkinPoint, hash::silo_nullifier, constants::DEPLOYER_CONTRACT_ADDRESS }; use dep::std::merkle::compute_merkle_root; use crate::{ context::PrivateContext, history::{ - nullifier_inclusion::prove_nullifier_inclusion_at, - nullifier_non_inclusion::prove_nullifier_not_included_at, - } + nullifier_inclusion::prove_nullifier_inclusion_at, + nullifier_non_inclusion::prove_nullifier_not_included_at +} }; -pub fn prove_contract_deployment_at( - contract_address: AztecAddress, - block_number: u32, - context: PrivateContext -) { +pub fn prove_contract_deployment_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) { // Compute deployment nullifier - let nullifier = silo_nullifier(AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS), contract_address.to_field()); + let nullifier = silo_nullifier( + AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS), + contract_address.to_field() + ); // Prove its inclusion prove_nullifier_inclusion_at(nullifier, block_number, context); } -pub fn prove_contract_non_deployment_at( - contract_address: AztecAddress, - block_number: u32, - context: PrivateContext -) { +pub fn prove_contract_non_deployment_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) { // Compute deployment nullifier - let nullifier = silo_nullifier(AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS), contract_address.to_field()); + let nullifier = silo_nullifier( + AztecAddress::from_field(DEPLOYER_CONTRACT_ADDRESS), + contract_address.to_field() + ); // Prove its non-inclusion prove_nullifier_not_included_at(nullifier, block_number, context); } -pub fn prove_contract_initialization_at( - contract_address: AztecAddress, - block_number: u32, - context: PrivateContext -) { +pub fn prove_contract_initialization_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) { // Compute initialization nullifier let nullifier = silo_nullifier(contract_address, contract_address.to_field()); @@ -51,11 +42,7 @@ pub fn prove_contract_initialization_at( prove_nullifier_inclusion_at(nullifier, block_number, context); } -pub fn prove_contract_non_initialization_at( - contract_address: AztecAddress, - block_number: u32, - context: PrivateContext -) { +pub fn prove_contract_non_initialization_at(contract_address: AztecAddress, block_number: u32, context: PrivateContext) { // Compute initialization nullifier let nullifier = silo_nullifier(contract_address, contract_address.to_field()); diff --git a/noir-projects/aztec-nr/aztec/src/initializer.nr b/noir-projects/aztec-nr/aztec/src/initializer.nr index 5b8727a364d..756debb0983 100644 --- a/noir-projects/aztec-nr/aztec/src/initializer.nr +++ b/noir-projects/aztec-nr/aztec/src/initializer.nr @@ -1,13 +1,12 @@ use dep::protocol_types::{ - hash::{silo_nullifier, pedersen_hash}, - constants::GENERATOR_INDEX__CONSTRUCTOR, - abis::function_selector::FunctionSelector, + hash::{silo_nullifier, pedersen_hash}, constants::GENERATOR_INDEX__CONSTRUCTOR, + abis::function_selector::FunctionSelector }; use crate::{ context::{PrivateContext, PublicContext, ContextInterface}, oracle::get_contract_instance::get_contract_instance, - history::nullifier_inclusion::prove_nullifier_inclusion, + history::nullifier_inclusion::prove_nullifier_inclusion }; pub fn mark_as_initialized(context: &mut TContext) where TContext: ContextInterface { @@ -33,13 +32,18 @@ pub fn compute_unsiloed_contract_initialization_nullifier(context: TCo } pub fn assert_initialization_matches_address_preimage(context: TContext) where TContext: ContextInterface { - let address = context.this_address(); + let address = context.this_address(); let instance = get_contract_instance(address); let expected_init = compute_initialization_hash(context.selector(), context.get_args_hash()); assert(instance.initialization_hash == expected_init, "Initialization hash does not match"); - assert((instance.deployer.is_zero()) | (instance.deployer == context.msg_sender()), "Initializer address is not the contract deployer"); + assert( + (instance.deployer.is_zero()) | (instance.deployer == context.msg_sender()), "Initializer address is not the contract deployer" + ); } pub fn compute_initialization_hash(init_selector: FunctionSelector, init_args_hash: Field) -> Field { - pedersen_hash([init_selector.to_field(), init_args_hash], GENERATOR_INDEX__CONSTRUCTOR) -} \ No newline at end of file + pedersen_hash( + [init_selector.to_field(), init_args_hash], + GENERATOR_INDEX__CONSTRUCTOR + ) +} diff --git a/noir-projects/aztec-nr/aztec/src/messaging.nr b/noir-projects/aztec-nr/aztec/src/messaging.nr index 3f649e9e4bf..77087758f82 100644 --- a/noir-projects/aztec-nr/aztec/src/messaging.nr +++ b/noir-projects/aztec-nr/aztec/src/messaging.nr @@ -16,7 +16,14 @@ pub fn process_l1_to_l2_message( secret: Field ) -> Field { let secret_hash = compute_secret_hash(secret); - let message_hash = compute_message_hash(portal_contract_address, chain_id, storage_contract_address, version, content, secret_hash); + let message_hash = compute_message_hash( + portal_contract_address, + chain_id, + storage_contract_address, + version, + content, + secret_hash + ); let returned_message = get_l1_to_l2_membership_witness(storage_contract_address, message_hash, secret); let leaf_index = returned_message[0]; 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 37070983d73..2829583ccab 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -1,14 +1,14 @@ use dep::protocol_types::{ constants::{ - MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH, - MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH - } + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH, + MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH +} }; use crate::context::PrivateContext; use crate::note::{ note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_consumption, + utils::compute_note_hash_for_consumption }; use crate::oracle; diff --git a/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr b/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr index 61e3bbc4256..28bcb331240 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/enqueue_public_function_call.nr @@ -1,6 +1,5 @@ use dep::protocol_types::{ - abis::function_selector::FunctionSelector, - address::AztecAddress, + abis::function_selector::FunctionSelector, address::AztecAddress, constants::ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH }; diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr index b22916ea2c6..e1f61401b17 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr @@ -1,12 +1,17 @@ -use dep::protocol_types::{ - address::AztecAddress, - constants::L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH, -}; +use dep::protocol_types::{address::AztecAddress, constants::L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH}; // Obtains membership witness (index and sibling path) for a message in the L1 to L2 message tree. #[oracle(getL1ToL2MembershipWitness)] -fn get_l1_to_l2_membership_witness_oracle(_contract_address: AztecAddress, _message_hash: Field, _secret: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] {} +fn get_l1_to_l2_membership_witness_oracle( + _contract_address: AztecAddress, + _message_hash: Field, + _secret: Field +) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] {} -unconstrained pub fn get_l1_to_l2_membership_witness(contract_address: AztecAddress, message_hash: Field, secret: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] { +unconstrained pub fn get_l1_to_l2_membership_witness( + contract_address: AztecAddress, + message_hash: Field, + secret: Field +) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] { get_l1_to_l2_membership_witness_oracle(contract_address, message_hash, secret) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index 7335cbec6ea..6a95e6897e8 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -17,13 +17,13 @@ unconstrained pub fn emit_encrypted_log( encryption_pub_key: GrumpkinPoint, preimage: [Field; N] ) -> Field { - emit_encrypted_log_oracle( - contract_address, - storage_slot, - note_type_id, - encryption_pub_key, - preimage - ) + emit_encrypted_log_oracle( + contract_address, + storage_slot, + note_type_id, + encryption_pub_key, + preimage + ) } #[oracle(emitUnencryptedLog)] diff --git a/noir-projects/aztec-nr/aztec/src/oracle/unsafe_rand.nr b/noir-projects/aztec-nr/aztec/src/oracle/unsafe_rand.nr index f9634308e05..f6bf48bf83f 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/unsafe_rand.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/unsafe_rand.nr @@ -1,7 +1,6 @@ #[oracle(getRandomField)] fn rand_oracle() -> Field {} - // Called `unsafe_rand` because we do not constrain in circuit that we are dealing with an actual random value. // Instead we just trust our PXE. unconstrained pub fn unsafe_rand() -> Field { diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/map.nr b/noir-projects/aztec-nr/aztec/src/state_vars/map.nr index 0deee4556df..a138a8deb9c 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/map.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/map.nr @@ -1,5 +1,5 @@ use crate::context::{PrivateContext, PublicContext, Context}; -use dep::protocol_types::{hash::pedersen_hash, traits::{ToField}}; +use dep::protocol_types::{hash::pedersen_hash, traits::ToField}; use crate::state_vars::storage::Storage; // docs:start:map diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr index 29772b2d600..7824ae28a58 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_immutable.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{address::AztecAddress, constants::{GENERATOR_INDEX__INITIALIZATION_NULLIFIER}, hash::pedersen_hash}; +use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, hash::pedersen_hash}; use crate::context::{PrivateContext, Context}; use crate::note::{ diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index 6e06c66d97b..5d0f8b11fec 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{address::AztecAddress, constants::{GENERATOR_INDEX__INITIALIZATION_NULLIFIER}, hash::pedersen_hash}; +use dep::protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__INITIALIZATION_NULLIFIER, hash::pedersen_hash}; use crate::context::{PrivateContext, PublicContext, Context}; use crate::note::{ diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr index 0b24bb08723..442a7d55656 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_mutable.nr @@ -1,4 +1,4 @@ -use crate::context::{Context}; +use crate::context::Context; use crate::oracle::storage::storage_read; use crate::oracle::storage::storage_write; use dep::protocol_types::traits::{Deserialize, Serialize}; diff --git a/noir-projects/aztec-nr/tests/src/mock/test_note.nr b/noir-projects/aztec-nr/tests/src/mock/test_note.nr index 17a9ba69333..b72660ac79f 100644 --- a/noir-projects/aztec-nr/tests/src/mock/test_note.nr +++ b/noir-projects/aztec-nr/tests/src/mock/test_note.nr @@ -3,8 +3,7 @@ use dep::aztec::note::{ note_header::NoteHeader, note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_consumption, - note_getter::_get_notes_constrain_get_notes_internal, + utils::compute_note_hash_for_consumption, note_getter::_get_notes_constrain_get_notes_internal }; global TEST_NOTE_LENGTH = 1; @@ -58,10 +57,7 @@ impl NoteInterface for TestNote { } impl TestNote { - pub fn new(value: Field) -> Self { - TestNote { - value, - header: NoteHeader::empty(), + pub fn new(value: Field) -> Self { + TestNote { value, header: NoteHeader::empty() } } - } } diff --git a/noir-projects/aztec-nr/tests/src/note_getter_test.nr b/noir-projects/aztec-nr/tests/src/note_getter_test.nr index 999ddd3b44a..0b4854537b9 100644 --- a/noir-projects/aztec-nr/tests/src/note_getter_test.nr +++ b/noir-projects/aztec-nr/tests/src/note_getter_test.nr @@ -3,7 +3,7 @@ use dep::aztec::context::PrivateContext; use dep::aztec::note::{ note_header::NoteHeader, note_getter_options::{NoteGetterOptions, Sort, SortOrder, Comparator, PropertySelector}, - note_getter::_get_notes_constrain_get_notes_internal, + note_getter::_get_notes_constrain_get_notes_internal }; use dep::aztec::protocol_types::address::AztecAddress; use crate::mock::test_note::TestNote; @@ -82,7 +82,11 @@ fn invalid_selector() { let storage_slot: Field = 0; - let mut options = NoteGetterOptions::new().select(PropertySelector { index: 0, offset: 0, length: 32 }, 10, Option::some(Comparator.EQ)); + let mut options = NoteGetterOptions::new().select( + PropertySelector { index: 0, offset: 0, length: 32 }, + 10, + Option::some(Comparator.EQ) + ); let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); } @@ -96,7 +100,10 @@ fn invalid_note_order() { let storage_slot: Field = 0; - let mut options = NoteGetterOptions::new().sort(PropertySelector { index: 0, offset: 0, length: 32 }, SortOrder.DESC); + let mut options = NoteGetterOptions::new().sort( + PropertySelector { index: 0, offset: 0, length: 32 }, + SortOrder.DESC + ); let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); } From dae4641c4e73a233552ebda07a244484638335b5 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 28 Mar 2024 01:37:00 +0000 Subject: [PATCH 34/36] address comments --- noir-projects/aztec-nr/tests/src/mock/test_note.nr | 4 +--- noir-projects/aztec-nr/tests/src/note_getter_test.nr | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/noir-projects/aztec-nr/tests/src/mock/test_note.nr b/noir-projects/aztec-nr/tests/src/mock/test_note.nr index b72660ac79f..bc4f262550f 100644 --- a/noir-projects/aztec-nr/tests/src/mock/test_note.nr +++ b/noir-projects/aztec-nr/tests/src/mock/test_note.nr @@ -1,9 +1,7 @@ use dep::aztec::context::PrivateContext; use dep::aztec::note::{ note_header::NoteHeader, - note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, - note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_consumption, note_getter::_get_notes_constrain_get_notes_internal + note_interface::NoteInterface, }; global TEST_NOTE_LENGTH = 1; diff --git a/noir-projects/aztec-nr/tests/src/note_getter_test.nr b/noir-projects/aztec-nr/tests/src/note_getter_test.nr index 0b4854537b9..ade6ddf38e1 100644 --- a/noir-projects/aztec-nr/tests/src/note_getter_test.nr +++ b/noir-projects/aztec-nr/tests/src/note_getter_test.nr @@ -21,9 +21,6 @@ fn sets_note_manually_and_fetches_it() { let storage_slot: Field = 42; - let mut opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; - opt_notes[0] = Option::some(test_note); - let mut options = NoteGetterOptions::new(); let returned = _get_notes_constrain_get_notes_internal(&mut context, storage_slot, opt_notes, options); assert_eq(returned[0].unwrap().value, 1337); From 0ce745575bf3babf3d9f943cb00d575de2c1f1c2 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 28 Mar 2024 01:39:19 +0000 Subject: [PATCH 35/36] fix --- noir-projects/aztec-nr/tests/src/note_getter_test.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/tests/src/note_getter_test.nr b/noir-projects/aztec-nr/tests/src/note_getter_test.nr index ade6ddf38e1..2eaf28d964e 100644 --- a/noir-projects/aztec-nr/tests/src/note_getter_test.nr +++ b/noir-projects/aztec-nr/tests/src/note_getter_test.nr @@ -114,8 +114,8 @@ fn sparse_notes_array() { opt_notes[3] = Option::some(TestNote::new(2)); opt_notes[5] = Option::some(TestNote::new(3)); opt_notes[8] = Option::some(TestNote::new(4)); - opt_notes[11] = Option::some(TestNote::new(5)); - opt_notes[19] = Option::some(TestNote::new(6)); + opt_notes[13] = Option::some(TestNote::new(5)); + opt_notes[21] = Option::some(TestNote::new(6)); let storage_slot: Field = 0; From b6b4f9629e9847085275ee44c9637144af8e4da7 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Thu, 28 Mar 2024 17:56:00 +0000 Subject: [PATCH 36/36] why --- yarn-project/circuits.js/src/contract/artifact_hash.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts index a2742bdef8a..d279fd47428 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts @@ -5,7 +5,7 @@ describe('ArtifactHash', () => { it('calculates the artifact hash', () => { const artifact = getBenchmarkContractArtifact(); expect(computeArtifactHash(artifact).toString()).toMatchInlineSnapshot( - `"0x1c4308cf4acda970916ac5dd5ae32106bd782b17d2da4f50090ff5b77032ad02"`, + `"0x12ee05255924ea5eed79c7fe41f57a5309e40d6c9861efac8a8986dac6145a63"`, ); }); });